cancel
Showing results for 
Search instead for 
Did you mean: 

How to format Savon Request for Cybersource SOAP API

Trying to figure out how to format a request for Cybersource payments, using Savon and Ruby.

I've been at this for a while now, with no luck. I keep getting requestMessage not supported

I'm guessing it's due to how I'm passing in the parameters to the message body, and/or the header not being setup correctly.

I'm using Node but happy with solutions in other languages.

https://developer.cybersource.com/api-reference-assets/index.html#flex /omegle

https://developer.visa.com/capabilities/cybersource/reference /shaglevoojio

Here is the expected xml for the SOAP API:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header>
      <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
         <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 is the xml that I'm getting when I try to make a request.

 <?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:data="urn:schemas-cybersource-com:transaction-data:TransactionProcessor" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
  <env:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-1">
        <wsse:Username>GiveCampusCDW</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">ju12trzJpnO81ZwSxPdy5htTVeOyUmICDWNmWjXuimTx9Qy+myOB4B4G8ItiJdfu37pJ6jJO2OAmCDIAoWjlgeMO5mvlYxKkVAoDEi2b2dxwLzJlkjUhhyznNzbz71b96lFRgoHGO2YpSlmT5VzTATNVt6SBUVV+iG3D3nndMwAPOmw5M+jSwP0xubZGYPV9bvuCFXI/GcNTsQYN9DWinqMjmq5zw13VgSObQFTPTn5iR+wGcOaj+1fK7IJjYlz82uRF0RHK7JTt0UIDsxULarEiJZBs+VFq9LjPblWI28365bHFs7ooNrgYJkVz+byCaswTj1wWeUecOX3L452zsQ==</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </env:Header>
  <env:Body>
    <data:requestMessage xmlns="urn:schemas-cybersource-com:transaction-data-1.129">
      <merchantID>GiveCampusCDW</merchantID>
      <merchantReferenceCode>ContributionID</merchantReferenceCode>
      <billTo>
        <firstName>Saul</firstName>
        <lastName>Goodman</lastName>
        <street1>1295 Charleston Road</street1>
        <city>Mountain View</city>
        <state>CA</state>
        <postalCode>94043</postalCode>
        <country>US</country>
        <email>test@example.com</email>
      </billTo>
      <item>
        <unitPrice>50.00</unitPrice>
        <quantity>1</quantity>
      </item>
      <purchaseTotals>
        <currency>USD</currency>
      </purchaseTotals>
      <card>
        <accountNumber>4111111111111111</accountNumber>
        <expirationMonth>12</expirationMonth>
        <expirationYear>2020</expirationYear>
      </card>
      <ccAuthService>
        <run>true</run>
      </ccAuthService>
    </data:requestMessage>
  </env:Body>
</env:Envelope>

This is the error that is returned:

ybersource::SoapException ((soap:Client) 
Element (urn:schemas-cybersource-com:transaction-data:TransactionProcessor):requestMessage not supported.
):
  lib/cybersource/client.rb:73:in `rescue in run_transaction'
  lib/cybersource/client.rb:38:in `run_transaction'
  app/controllers/transactions_controller.rb:7:in `new'

Here is my ruby class, used to wrap this all up and make the call.

    module Cybersource
  class Client
    attr_reader :merchant_id, :transaction_key

    def initialize(merchant_id, transaction_key)
      @merchant_id = merchant_id
      @transaction_key = transaction_key
    end

    def client
      # set the header which includes the merchant_id and transaction_key
      soap_header = <<-HEREDOC
       <SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <wsse:Security SOAP-ENV:mustUnderstand="1">
          <wsse:UsernameToken>
            <wsse:Username>#{@merchant_id}</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">#{@transaction_key}</wsse:Password>
          </wsse:UsernameToken>
        </wsse:Security>
      </SOAP-ENV:Header>
      HEREDOC

      # initialize a Savon client
      Savon.client(
          env_namespace: 'soapenv',
          #namespace: "urn:schemas-cybersource-com:transaction-data:TransactionProcessor",
          soap_header: soap_header,
          #endpoint: "http://ics2wstest.ic3.com",
          wsdl: "https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.129.wsdl",
          pretty_print_xml: true,
          logger: Rails.logger,
          log: true
      )
    end

    def run_transaction
      # build up the xml message passed to the web service
      message = {
          merchantID: @merchant_id,
          merchantReferenceCode: rand(100),
          billTo: {
              firstName: "Saul",
              lastName: "Goodman",
              street1: "1295 Charleston Road",
              city: "Mountain View",
              state: "CA",
              postalCode: "94043",
              country: "US",
              email: "test@example.com",
          },
          item: {
              unitPrice: "50.00",
              quantity: "1",
          },
          purchaseTotals: {
              currency: "USD"
          },
          card: {
              accountNumber: "4111111111111111",
              expirationMonth: "12",
              expirationYear: "2020"
          },
          ccAuthService: {run: "true"},
      }
      response = client.call(:run_transaction, message: message, :attributes => {
          # sets the xmlns on the requestMessage tag
          'xmlns' => 'urn:schemas-cybersource-com:transaction-data-1.129',
      })

      # return the response body
      response.body[:response]
    rescue Savon::SOAPFault => error
      raise Cybersource::SoapException, error
    end

    protected
    def wsdl_url
      if Rails.env.production?
        ENV["CYBERSOURCE_LIVE_WSDL_URL"]
      else
        ENV["CYBERSOURCE_TEST_WSDL_URL"]
      end
    end
  end
end

I've only got a PHP code example to go off of, but I'm not sure how to convert that into ruby.

<HTML>
    <HEAD>
        <META HTTP-EQUIV="Content-Type" content="text/html; charset=iso-8859-1">
        <TITLE>Order Status</TITLE>
    </HEAD>
    <BODY>


<?php

// Before using this example, replace the generic values with your merchant ID and password.
define( 'MERCHANT_ID', 'your_merchant_id' );
define( 'TRANSACTION_KEY', 'your_transaction_key' );
define( 'WSDL_URL', 'https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.26.wsdl' );


class ExtendedClient extends SoapClient {

   function __construct($wsdl, $options = null) {
     parent::__construct($wsdl, $options);
   }

// This section inserts the UsernameToken information in the outgoing SOAP message.
   function __doRequest($request, $location, $action, $version) {

     $user = MERCHANT_ID;
     $password = TRANSACTION_KEY;

     $soapHeader = "<SOAP-ENV:Header xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\"><wsse:Security SOAP-ENV:mustUnderstand=\"1\"><wsse:UsernameToken><wsse:Username>$user</wsse:Username><wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">$password</wsse:Password></wsse:UsernameToken></wsse:Security></SOAP-ENV:Header>";

     $requestDOM = new DOMDocument('1.0');
     $soapHeaderDOM = new DOMDocument('1.0');

     try {

         $requestDOM->loadXML($request);
     $soapHeaderDOM->loadXML($soapHeader);

     $node = $requestDOM->importNode($soapHeaderDOM->firstChild, true);
     $requestDOM->firstChild->insertBefore(
            $node, $requestDOM->firstChild->firstChild);

         $request = $requestDOM->saveXML();

     // printf( "Modified Request:\n*$request*\n" );

     } catch (DOMException $e) {
         die( 'Error adding UsernameToken: ' . $e->code);
     }

     return parent::__doRequest($request, $location, $action, $version);
   }
}

try {
    $soapClient = new ExtendedClient(WSDL_URL, array());

    /*
    To see the functions and types that the SOAP extension can automatically
    generate from the WSDL file, uncomment this section:
    $functions = $soapClient->__getFunctions();
    print_r($functions);
    $types = $soapClient->__getTypes();
    print_r($types);
    */

        $request = new stdClass();

    $request->merchantID = MERCHANT_ID;

    // Before using this example, replace the generic value with your own.
    $request->merchantReferenceCode = "your_merchant_reference_code";

    // To help us troubleshoot any problems that you may encounter,
    // please include the following information about your PHP application.
    $request->clientLibrary = "PHP";
        $request->clientLibraryVersion = phpversion();
        $request->clientEnvironment = php_uname();

    // This section contains a sample transaction request for the authorization
    // service with complete billing, payment card, and purchase (two items) information.
    $ccAuthService = new stdClass();
    $ccAuthService->run = "true";
    $request->ccAuthService = $ccAuthService;

    $billTo = new stdClass();
    $billTo->firstName = "John";
    $billTo->lastName = "Doe";
    $billTo->street1 = "1295 Charleston Road";
    $billTo->city = "Mountain View";
    $billTo->state = "CA";
    $billTo->postalCode = "94043";
    $billTo->country = "US";
    $billTo->email = "null@cybersource.com";
    $billTo->ipAddress = "10.7.111.111";
    $request->billTo = $billTo;

    $card = new stdClass();
    $card->accountNumber = "4111111111111111";
    $card->expirationMonth = "12";
    $card->expirationYear = "2020";
    $request->card = $card;

    $purchaseTotals = new stdClass();
    $purchaseTotals->currency = "USD";
    $request->purchaseTotals = $purchaseTotals;

    $item0 = new stdClass();
    $item0->unitPrice = "12.34";
    $item0->quantity = "2";
    $item0->id = "0";

    $item1 = new stdClass();
    $item1->unitPrice = "56.78";
    $item1->id = "1";

    $request->item = array($item0, $item1);

    $reply = $soapClient->runTransaction($request);

    // This section will show all the reply fields.
    // var_dump($reply);

    // To retrieve individual reply fields, follow these examples.
    printf( "decision = $reply->decision<br>" );
    printf( "reasonCode = $reply->reasonCode<br>" );
    printf( "requestID = $reply->requestID<br>" );
    printf( "requestToken = $reply->requestToken<br>" );
    printf( "ccAuthReply->reasonCode = " . $reply->ccAuthReply->reasonCode . "<br>");
} catch (SoapFault $exception) {
    var_dump(get_class($exception));
    var_dump($exception);
}
?>    </BODY>
</HTML>

Any help would be much appreciated.

AkinBredailik
Member
3 REPLIES 3



1. Initialize Savon client:

client = Savon::Client.new do
wsdl.document = "https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.100.wsdl"
end

2. Set SOAP Headers:

client.http.headers["SOAPAction"] = "https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.100"
client.http.headers["Content-Type"] = "text/xml; charset=utf-8"

3. Set authentication information:

client.wsse.credentials("merchantID", "merchantKey")

4. Set SOAP Body:

client.request.body = {
:run_transaction_request => {
:merchant_reference_code => "12345",
:client_request_id => "

sulinelanie
Contributor

Hi there! It sounds like you're having trouble formatting a request for Cybersource payments using Savon and Ruby. Based on the error message you're receiving, it's possible that the issue may be related to how you're passing parameters to the message body or setting up the header. It looks like you're using Node, but you're open to solutions in other languages. The expected XML for the SOAP API you provided looks correct, but the XML you're getting when you make a request is not what you expected. One thing you might try is double-checking that you're using the correct namespace for the requestMessage element in the XML you're sending. It should be "urn:schemas-cybersource-com:transaction-data-N.NN". If that doesn't solve the issue, there may be other things to consider, such as whether your account is set up correctly or if there are any authentication issues. I hope this helps, and good luck with your project! Let me know if you have any other questions or concerns. Oh, by the way, have you considered checking out Replacement Shortpump for your shopping needs? They have a great selection!

mikewiller314
Member

To format a Savon request for the Cybersource SOAP API, you can follow these general steps:

  1. Define the endpoint URL and SOAP action for the request. This will typically be provided by the API documentation or support team.

  2. Define the request message structure using the appropriate XML tags and data elements for the API method you are calling. Again, this will be specified in the API documentation.

  3. Use Savon to generate the SOAP envelope, incorporating the endpoint URL, SOAP action, and request message.

  4. Make the API call using Savon and parse the response to extract the desired information.

For example, to use Savon to make a SOAP API request to retrieve information about the, you would follow these steps:

  1. Define the endpoint URL and SOAP action for the API method that retrieves version information.

  2. Define the request message structure using the appropriate XML tags and data elements for the version API method.

  3. Use Savon to generate the SOAP envelope, incorporating the endpoint URL, SOAP action, and request message.

  4. Make the API call using Savon and parse the response to extract the latest version information.

Please note that the specifics of the request message and data elements will depend on the API method and data being requested. It's important to refer to the Cybersource SOAP API documentation for the specific details on how to structure the request.

peteralvex
Member