SOAP-based code changes required by AFTM

There are four areas that require changes in your SOAP-based code to use AFTM. These are:

  1. Use your account-specific URL end point for AFTM-supported calls.
  2. Use only a limited subset of SOAP API functions in your AFTM sessions. (For more information about the object types and error messages, refer to the standard Responsys SOAP API Guide.)
  3. Use specific functions for merging members and triggering email or SMS messages.
  4. Handling errors and exceptions.

Use your account-specific URL end point

Once the secondary failover account is provisioned, you will receive an account-specific URL endpoint from Oracle that must be used in your AFTM software code.

If your Responsys account is globally routed, your URL endpoint will be a unique global routing endpoint. See Global Routing for more details.

If your account is on a legacy pod, the format of this URL will be similar to the following:

https://wsX-companyABC.responsys.net/webservices/services/ResponsysWSService

where wsX refers to the pod (for example, ws2 indicates the interact2 pod), and companyABC is the account-specific identifier, such as a company name.

If you have not received your account-specific URL endpoint, please contact your Customer Success Manager (CSM).

Use only a limited subset of SOAP API functions

Only the following standard API functions are processed through AFTM during service disruptions:

  • login
  • loginWithCertificate
  • authenticateServer
  • logout
  • retrieveListMembers - Use this function only when your code also uses an AFTM-specific call (that is, HAMergeTriggerEmail or HAMergeTriggerSMS). The retrieveListMembers call will work on both primary and secondary accounts, but it cannot detect problems and fail over, as the AFTM-specific calls do.

When using the SOAP session management calls, you must use the account-specific URL endpoint. Do not use other standard API functions in the same sessions as the AFTM endpoints. If the same API client code makes AFTM and non-AFTM API calls to the AFTM endpoint, be aware that:

  • The entire transaction in the same sessionID may be invalidated during a failover. There is no option of recovery.
  • Any non-AFTM API calls that lands on the secondary node causes the system to throw the exception "API_NOT_ALLOWED_IN_SECONDARY" in the HTTP Response. If you mix AFTM and standard API calls in one sessionID, the system defaults to using the lower standard API throttling limits. This may degrade overall performance, because AFTM calls use higher tiered limits.

The following calls are specific to AFTM. Use them as described in the next section:

  • HaMergeTriggerEmail
  • HaMergeTriggerSMS

Use specific functions for merging members and triggering email or SMS messages

Two specific functions called HaMergeTriggerEmail and HaMergeTriggerSMS are available specifically in AFTM. They combine into one transaction the merging of members into a profile list and the triggering of messages to those members. Responsys campaigns that already exist can be sent up to 200 members of a profile list. When using AFTM and SOAP, these functions must be used to ensure integrity of data in the primary and secondary failover accounts, as well as automatically switching from the primary to the secondary account during a service disruption. These functions and their input and output parameters are described in the sections that follow.

HaMergeTriggerEmail

This function can be used for triggering both transactional and promotional emails. However, promotional emails will fail on the secondary account during failover. Both merging members and the email trigger will fail.

Syntax

TriggerResult[] = service.HaMergeTriggerEmail (RecordData recordData, ListMergeRule mergeRule,  InteractObject campaign, TriggerData[] triggerData)

Request Arguments

Name

Type

Description

recordData

RecordData

Array of RecordData objects that contain field and record data

mergeRule

ListMergeRule

Defines the merge rules for how to handle the record data

campaign

InteractObject

Campaign name and folder

triggerData

TriggerData[]

An array of TriggerData objects that consists of an OptionalData object array

The TriggerData object has the list of name/value pair parameters needed for triggering messages. OptionalData[] has optional name/value pair parameters associated with List member.

Response

Call returns an array of TriggerResult objects. This object has the following properties:

Name

Type

Description

recipientId

Long

Interact internal recipient ID (RIID_) for the individual to whom the message was sent

success

Boolean

Success flag for trigger message request

errorMessage

String

NO_RECIPIENT_FOUND

MULTIPLE_RECIPIENTS_FOUND

HaMergeTriggerSMS

Syntax

TriggerResult[] = service.HaMergeTriggerSms (RecordData recordData, ListMergeRule mergeRule, InteractObject campaign, TriggerData[] triggerData)

Request Arguments

Name

Type

Description

RecordData

RecordData

Array of RecordData objects that contain field and record data

mergeRule

ListMergeRule

Defines the merge rules for how to handle the record data

campaign

InteractObject

Campaign name and folder

triggerData

TriggerData[]

An array of TriggerData objects that consists of an OptionalData object array

The TriggerData object has the list of name/value pair parameters needed for triggering messages. OptionalData[] has optional name/value pair parameters associated with the List member.

Response

Call returns an array of TriggerResult objects. This object has the following properties:

Name

Type

Description

recipientId

Long

Interact internal recipient ID (RIID_) for the individual to whom the message was sent

success

Boolean

Success flag for trigger message request

errorMessage

String

NO_RECIPIENT_FOUND

MULTIPLE_RECIPIENTS_FOUND

Sample code for SOAP

Creating TriggerData

TriggerData[] triggerData = null;
if (numOfRecipientsInCall > 0) {
      triggerData = new TriggerData[numOfRecipientsInCall];
 }
 for (int i = 0; i < numOfRecipientsInCall; i++) {
       triggerData[i] = new TriggerData();
       //How many campaign variables you want to specify 
       OptionalData[] variables = null;
       if (numOfVariables > 0) {
                variables = new OptionalData[numOfVariables];
        }
        for (int j = 0; j < numOfVariables; j++) {
                variables[j] = new OptionalData();
                variables[j].setName(varName);
                variables[j].setValue(carValue);
            }
            triggerData[i].setOptionalData(variables);
        }
}

Making an HaMergeTriggerEmail call

try {
    HaMergeTriggerEmail haMergeTriggerEmail = new HaMergeTriggerEmail();
    InteractObject campaignObj = new InteractObject();
    campaignObj.setFolderName(folderNameForTrigger);
    campaignObj.setObjectName(campaignName);
    haMergeTriggerEmail.setRecordData(recordData);
    haMergeTriggerEmail.setMergeRule(listMergeRule);
    haMergeTriggerEmail.setCampaign(campaignObj);
    haMergeTriggerEmail.setTriggerData(triggerData);
    HaMergeTriggerEmailResponse resp = stub.HaMergeTriggerEmail(haMergeTriggerEmail,
                    sessionHeader);
    if (resp == null){
            	sop("Failed to create result ");
     }
     else {
            	com.rsys.ws.TriggerResult[] trRes =resp.getResult();
            	if (trRes == null || trRes.length == 0) {
            	    sop("Failed to create result ");
            	} else {
            	    int i = 0;
            	    for (com.rsys.ws.TriggerResult res: trRes){
            	        if (res == null){
            		sop("Record["+i+"] - Failed to create Result");
            	        }
            	        else if (res.getSuccess()){
            		sop("Record["+i+"] - Success");
                     }
            	        else {
            		sop("Record["+i+"] - Failed:"+ res.getErrorMessage());
                     }
            	  }
         }
    }
}
catch (TriggeredMessageFault trgMsgFaultEx) {
            sop("TriggeredMessageFault HaMergeTriggerEmail");
            sop("Exception Code = " + trgMsgFaultEx.getFaultMessage().getExceptionCode());
            sop("Exception Msg  = " + trgMsgFaultEx.getFaultMessage().getExceptionMessage());
}
catch (UnexpectedErrorFault unexpectedEx) {
            sop("unexpectedEx HaMergeTriggerEmail");
            sop("Exception Code = " + unexpectedEx.getFaultMessage().getExceptionCode());
            sop("Exception Msg  = " + unexpectedEx.getFaultMessage().getExceptionMessage());
        }
        catch (UnrecoverableErrorFault unexpectedEx) {
            sop("UnrecoverableError HaMergeTriggerEmail");
            sop("Exception Code = " + unexpectedEx.getFaultMessage().getExceptionCode());
            sop("Exception Msg  = " + unexpectedEx.getFaultMessage().getExceptionMessage());
        }
        catch (RemoteException remoteEx) {
            sop("remoteEx HaMergeTriggerEmail");
            sop("Exception Msg = " + remoteEx.getMessage());
        }

Making an HaMergeTriggerSms call

try {
    HaMergeTriggerSms haMergeTriggerSms = new HaMergeTriggerSms();
    InteractObject campaignObj = new InteractObject();
    campaignObj.setFolderName(folderNameForTrigger);
    campaignObj.setObjectName(campaignName);
    haMergeTriggerSms.setRecordData(recordData);
    haMergeTriggerSms.setMergeRule(listMergeRule);
    haMergeTriggerSms.setCampaign(campaignObj);
    haMergeTriggerSms.setTriggerData(triggerData);
    HaMergeTriggerSmsResponse resp = stub.HaMergeTriggerSms(haMergeTriggerSms, sessionHeader);
    if (resp == null){
      		sop("Failed to create result ");
     }
     else {
                        com.rsys.ws.TriggerResult[] trRes =resp.getResult();
                        if (trRes == null || trRes.length == 0) {
                            sop("Failed to create result ");
                        } else {
                            int i = 0;
                            for (com.rsys.ws.TriggerResult res: trRes){
                                if (res == null){
                                    sop("Record["+i+"] - Failed to create Result");
                                }
                                else if (res.getSuccess()){
                                    sop("Record["+i+"] - Success");
                     }
                                else {
                                    sop("Record["+i+"] - Failed:"+ res.getErrorMessage());
                     }
              }
         }
    }
}
catch (TriggeredMessageFault trgMsgFaultEx) {
            sop("TriggeredMessageFault HaMergeTriggerSMS");
            sop("Exception Code = " + trgMsgFaultEx.getFaultMessage().getExceptionCode());
            sop("Exception Msg  = " + trgMsgFaultEx.getFaultMessage().getExceptionMessage());
}
catch (UnexpectedErrorFault unexpectedEx) {
            sop("unexpectedEx HaMergeTriggerSMS");
            sop("Exception Code = " + unexpectedEx.getFaultMessage().getExceptionCode());
            sop("Exception Msg  = " + unexpectedEx.getFaultMessage().getExceptionMessage());
}
catch (UnrecoverableErrorFault unexpectedEx) {
            sop("UnrecoverableError HaMergeTriggerSMS");
            sop("Exception Code = " + unexpectedEx.getFaultMessage().getExceptionCode());
            sop("Exception Msg  = " + unexpectedEx.getFaultMessage().getExceptionMessage());
        }


catch (RemoteException remoteEx) {
            sop("remoteEx HaMergeTriggerSMS");
            sop("Exception Msg = " + remoteEx.getMessage());
}

Handling errors and exceptions

Once the API requests are routed from one account to the other, a new session must be established. Therefore, your code must monitor responses for an exception for an invalid session, and then re-login with the same credentials used to access your primary Interact account.

  • If you receive an unrecoverable exception, your code should wait about 30 seconds and resubmit the request only once.
  • If there is no system response, your code can retry up to three times, with two minute intervals. If you still do not receive a response, close the session and re-log in.