function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Larry WeiburgLarry Weiburg 

Cybersource API Calls

Hi everyone,

I need to figure out how to make calls to Cybersource for payments and refunds in Apex, and I have the credentials to do so, but I'm not sure how to implement it.

Does anyone have any sample/simple code that accomplishes one of these? I don't know how to build the request and the errors I receive are all 'XML Parsing Error'.

Any help at all would be great.
Best Answer chosen by Larry Weiburg
DimondDimond
so you'll need to review a few thing. first the cybersource doc
http://apps.cybersource.com/library/documentation/dev_guides/SOAP_Toolkits/html/wwhelp/wwhimpl/js/html/wwhelp.htm#href=preface.html

then
https://help.salesforce.com/articleView?id=code_wsdl_to_package.htm&type=5

and if you just want to get a different error message, you could send this example as a payload

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsse:UsernameToken>
        <wsse:Username>yourMerchantID</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">yourPassword</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body>
    <requestMessage xmlns="urn:schemas-cybersource-com:transaction-data-N.NN">
      <merchantID>yourMerchantID</merchantID>
      <merchantReferenceCode>MRC-123</merchantReferenceCode>
      <billTo>
        <firstName>John</firstName>
        <lastName>Doe</lastName>
        <street1>1295 Charleston Road</street1>
        <city>Mountain View</city>
        <state>CA</state>
        <postalCode>94043</postalCode>
        <country>US</country>
        <email>null@cybersource.com</email>
      </billTo>
      <item id="0">
        <unitPrice>5.00</unitPrice>
        <quantity>1</quantity>
      </item>
      <item id="1">
        <unitPrice>10.00</unitPrice>
        <quantity>2</quantity>
      </item>
      <purchaseTotals>
        <currency>USD</currency>
      </purchaseTotals>
      <card>
        <accountNumber>4111111111111111</accountNumber>
        <expirationMonth>11</expirationMonth>
        <expirationYear>2020</expirationYear>
      </card>
      <ccAuthService run="true"/>
    </requestMessage>
  </soapenv:Body>
</soapenv:Envelope>

All Answers

DimondDimond
If you could provide what you have so far would be a good start so that specific questions could be answered. Otherwise this would be a good start. 
https://trailhead.salesforce.com/en/content/learn/modules/apex_integration_services/apex_integration_rest_callouts
Larry WeiburgLarry Weiburg

I haven't been able to find any examples of requests being sent to Cybersource from Salesforce Apex, so getting an 'XML Parse Error' hasn't helped direct me toward a solution.

Starting from page 75 is where it discusses what is required to request a credit service for refunding.

http://apps.cybersource.com/library/documentation/dev_guides/CC_Svcs_SO_API/Credit_Cards_SO_API.pdf

Here is where I'm supposed to send my test requests to.
https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/

Here's an example of what I'm trying to build.

String body= 
            '<requestMessage xmlns="urn:schemas-cybersource-com:transaction-data-1.155">'
            + '<merchantID>' + merchID + '</merchantID>'
            + '<merchantReferenceCode>' + referenceCode'</merchantReferenceCode>'
            + '</requestMessage>'
            + '<purchaseTotals>'
            + '<currency>' + currency + '</currency>'
            + '<grandTotalAmount>' + grandtotal + '</grandTotalAmount>'
            + '</purchaseTotals>'
            + '<CCCreditService run="true">'
            + '<captureRequestID>' + requestId + '<captureRequestID>'
            + '</CCCreditService>';
        
        Http http= new Http();
        HttpRequest req = new HttpRequest();
        req.setMethod('POST');
        req.setEndpoint(endpoint);
        req.setBody(body);
        HttpResponse response = http.send(req);
DimondDimond
this is prob what you're looking for

https://developer.salesforce.com/docs/atlas.en-us.218.0.apexcode.meta/apexcode/apex_xml_streaming_writing.htm

also don't forget create a remote site setting
Larry WeiburgLarry Weiburg
This will be helpful in putting it together, but I'm still not sure on how to build it, as in how it needs to look for the request to succeed.
DimondDimond
for that you'll have to refer to the documentation on what the request should look like. to make it easier, you should use a tool such as postman to test. once you figured out what the payload is supposed to be then you can construct it in apex. have you browsed to 
https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/ ...? seems that provides some valuable information. Try just making sure you can send something/anything out to your endpoint- just send a string of 'foo' out. 
Larry WeiburgLarry Weiburg
Sending just a string of 'foo' as the body returns the same error of Unexpected Response as before within the debug log. With faultcode of soap:Client and faultstring of XML parse error.

I've never used postman, how would you use that?

I've been browsing both the wsdl and xsd, and I haven't been able to figure out what it would take to give any kind of response that's not "XML parse error." The code snippet I included earlier includes all of the required fields, and I've tried various formats trying to include headers, usernames, passwords, but the error never changes. I definitely feel like I've just been running in circles.
DimondDimond
so you'll need to review a few thing. first the cybersource doc
http://apps.cybersource.com/library/documentation/dev_guides/SOAP_Toolkits/html/wwhelp/wwhimpl/js/html/wwhelp.htm#href=preface.html

then
https://help.salesforce.com/articleView?id=code_wsdl_to_package.htm&type=5

and if you just want to get a different error message, you could send this example as a payload

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsse:UsernameToken>
        <wsse:Username>yourMerchantID</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">yourPassword</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body>
    <requestMessage xmlns="urn:schemas-cybersource-com:transaction-data-N.NN">
      <merchantID>yourMerchantID</merchantID>
      <merchantReferenceCode>MRC-123</merchantReferenceCode>
      <billTo>
        <firstName>John</firstName>
        <lastName>Doe</lastName>
        <street1>1295 Charleston Road</street1>
        <city>Mountain View</city>
        <state>CA</state>
        <postalCode>94043</postalCode>
        <country>US</country>
        <email>null@cybersource.com</email>
      </billTo>
      <item id="0">
        <unitPrice>5.00</unitPrice>
        <quantity>1</quantity>
      </item>
      <item id="1">
        <unitPrice>10.00</unitPrice>
        <quantity>2</quantity>
      </item>
      <purchaseTotals>
        <currency>USD</currency>
      </purchaseTotals>
      <card>
        <accountNumber>4111111111111111</accountNumber>
        <expirationMonth>11</expirationMonth>
        <expirationYear>2020</expirationYear>
      </card>
      <ccAuthService run="true"/>
    </requestMessage>
  </soapenv:Body>
</soapenv:Envelope>
This was selected as the best answer
Larry WeiburgLarry Weiburg
EDIT: A lot of mistypes, but I'm able to get a StatusCode=200 and Status=OK now. Not sure how to check if it's fulfilling the transaction (refunding/crediting), as I can run the same request on the same record payment multiple times.
DimondDimond
thats good...can you not log in to see? What was the response? 
Larry WeiburgLarry Weiburg
The response just holds standard information along with requestToken, requestID, and success messages such as <c:decision>ACCEPT</c:decision> and <c:reasonCode>100</c:reasonCode>. 

As for logging in, in this particular scenario, I'm unable to log in to the CyberSource business center. Would you happen to know another way to see how these requests are being handled? Ideally, it wouldn't refund the same transaction if I request it multiple times, but I was wondering if that was intended for these test calls.

Otherwise, thank you very much for your help!

EDIT: Actually, would you have any recommendations on how to write a test class for a class that just has this method which makes a call to CyberSource for crediting/refunding? By that I mean what should I be trying to assert?
DimondDimond
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_testing_httpcalloutmock.htm
Maria MontgomeryMaria Montgomery
Hi Larry,

I am trying to make calls to Cybersource to process refunds using Apex. My understanding is that you were able to implement the code and I am wondering if you could share a sample of your final solution. I would appreciate your help.
Boss CoffeeBoss Coffee
Hi Maria,

Could you create a new question that has the details to your Cybersource inquiries?