SOAP-based code changes required by AFTM
There are four areas that require changes in your SOAP-based code to use AFTM. These are:
- Use your account-specific URL end point for AFTM-supported calls.
- 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.)
- Use specific functions for merging members and triggering email or SMS messages.
- 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.