SOAP requests using Savon - ruby

I dug as deep as I could but could not find a solution to my problem:
I want to send SOAP requests to ExactTarget API. I am trying to use Savon, but the requests it creates are different from those that worked with ExactTarget's API (I used Java previously) and in the end I get an error when running the Ruby script.
Below is the body of a working request that I am to create in Ruby:
<S:Body>
<RetrieveRequestMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">
<RetrieveRequest>
<ObjectType>BounceEvent</ObjectType>
<Properties>SendID</Properties>
<Properties>SubscriberKey</Properties>
<Properties>EventDate</Properties>
<Properties>SMTPCode</Properties>
<Properties>BounceCategory</Properties>
<Properties>SMTPReason</Properties>
<Properties>BounceType</Properties>
<Filter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="SimpleFilterPart">
<Property>SendID</Property>
<SimpleOperator>equals</SimpleOperator>
<Value>421939</Value>
</Filter>
</RetrieveRequest>
</RetrieveRequestMsg>
</S:Body>
Now here is the code I created in Ruby:
client = Savon.client do
wsdl 'https://webservice.s4.exacttarget.com/etframework.wsdl'
wsse_auth("user", "pass")
end
builder = Builder::XmlMarkup.new
builder.instruct!(:xml, encoding: "UTF-8")
#builder.RetrieveRequestMsg('xmlns'=>'http://exacttarget.com/wsdl/partnerAPI') do
builder.RetrieveRequest do
builder.ObjectType "BounceEvent"
builder.Properties "SendID"
builder.Properties "SubscriberKey"
end
#end
theBody = builder.target!
theBody.slice! '<?xml version="1.0" encoding="UTF-8"?>'
client.call(:retrieve, message: theBody)
..and here is the resulting request body:
<env:Body>
<tns:RetrieveRequestMsg>
<RetrieveRequest>
<ObjectType>BounceEvent</ObjectType>
<Properties>SendID</Properties>
<Properties>SubscriberKey</Properties>
</RetrieveRequest></tns:RetrieveRequestMsg>
</env:Body>
...and here is the resulting error I get:
<soap:Body>
<RetrieveResponseMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">
<OverallStatus>Error</OverallStatus>
<RequestID>5ce5cfae-85b4-4e76-b9dd-299e9a9ca871</RequestID>
</RetrieveResponseMsg>
</soap:Body>
Any help is greatly appreciated!

Rather than using Builder, try using Savons call method for generating a SOAP request.
ruby
response = client.call(:authenticate, message: { username: "luke", password: "secret" })
You have the wsdl, so you should be able to determine the method name and arguments. Calling .operations on the client will list all of the available operations that you can generate.

Related

invalid SOAP request needs experienced eye

TLDR: the solution can be found here
I'm using savon to make requests against a SOAP service. I know... Gross.
Regardless, I'm having trouble making Savon behave. The SOAP provider has this validator, which takes the following inputs:
Web Service: ProductData
Version: 1.0.0
Operation: getProductSellable
Endpoint: https://psproductdata100-stg.pcna.online
When I use the validator, I enter this xml:
<GetProductSellableRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/">
<wsVersion xmlns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/SharedObjects/">1.0.0</wsVersion>
</GetProductSellableRequest>
And I get this response body
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<GetProductSellableResponse xmlns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/">
<ErrorMessage xmlns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/SharedObjects/">
<code>110</code>
<description>Authentication Credentials Required</description>
</ErrorMessage>
</GetProductSellableResponse>
</s:Body>
</s:Envelope>
That response is valid because I did not provide my un/pw. If I do provide credentials, I get a full response. Below is a screenshot of that happening in my browser.
However, when I use Savon to make the same request
#!/usr/bin/env ruby
require 'savon'
require 'awesome_print'
require 'byebug'
require 'pry'
endpoint = 'https://psproductdata100-stg.pcna.online'
path = 'psProductData.svc?singleWsdl'
wsdl = "#{endpoint}/#{path}"
args = {
wsdl: wsdl,
log: true,
log_level: :debug,
pretty_print_xml: true,
element_form_default: :qualified
}
client = Savon.client(args) do
convert_request_keys_to :lower_camelcase
end
message = { ws_version: '1.0.0' }
response = client.call(:get_product_sellable) do
message(message)
end
ap response
The response does not come back as expected. The XML looks close to what was sent by the validator, but not exact.
Heres the request
D, [2018-04-26T18:01:00.471662 #89854] DEBUG -- : HTTPI /peer GET request to psproductdata100-stg.pcna.online (net_http)
I, [2018-04-26T18:01:00.979809 #89854] INFO -- : SOAP request: https://psproductdata100-stg.pcna.online/psProductData.svc
I, [2018-04-26T18:01:00.979886 #89854] INFO -- : SOAPAction: "getProductSellable", Content-Type: text/xml;charset=UTF-8, Content-Length: 501
D, [2018-04-26T18:01:00.980107 #89854] DEBUG -- : <?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:tns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ins0="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/SharedObjects/">
<env:Body>
<tns:GetProductSellableRequest>
<tns:wsVersion>1.0.0</tns:wsVersion>
</tns:GetProductSellableRequest>
</env:Body>
</env:Envelope>
And the response
D, [2018-04-26T18:01:00.980224 #89854] DEBUG -- : HTTPI /peer POST request to psproductdata100-stg.pcna.online (net_http)
I, [2018-04-26T18:01:01.650449 #89854] INFO -- : SOAP response (status 200)
D, [2018-04-26T18:01:01.650731 #89854] DEBUG -- : <?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<GetProductSellableResponse xmlns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/">
<ErrorMessage xmlns="http://www.promostandards.org/WSDL/ProductDataService/1.0.0/SharedObjects/">
<code>110</code>
<description>Version mismatch.</description>
</ErrorMessage>
</GetProductSellableResponse>
</s:Body>
</s:Envelope>
and the output from Savon
{
:get_product_sellable_response => {
:error_message => {
:code => "110",
:description => "Version mismatch.",
:#xmlns => "http://www.promostandards.org/WSDL/ProductDataService/1.0.0/SharedObjects/"
},
:#xmlns => "http://www.promostandards.org/WSDL/ProductDataService/1.0.0/"
},
:"#xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
:"#xmlns:xsd" => "http://www.w3.org/2001/XMLSchema"
}
Thanks to the other answers on this thread, I found this post. I read up on how namespaces work, as well as linked XSD files. By combining my new knowledge with that post, I was a able to build out something like this:
require 'savon'
require 'awesome_print'
require 'byebug'
require 'pry'
endpoint = 'https://psproductdata100-stg.pcna.online'
path = 'psProductData.svc?singleWsdl'
wsdl = "#{endpoint}/#{path}"
args = {
wsdl: wsdl,
log: false,
log_level: :debug,
pretty_print_xml: true,
element_form_default: :qualified
}
client = Savon.client(args) do
convert_request_keys_to :lower_camelcase
namespaces 'xmlns:shar' => 'http://www.promostandards.org/WSDL/ProductDataService/1.0.0/SharedObjects/'
end
message = {
'shar:wsVersion' => '1.0.0',
'shar:id' => 'REDACTED',
'shar:password' => 'REDACTED'
}
response = client.call(:get_product_sellable) do
message(message)
end
ap response.body[:get_product_sellable_response][:product_sellable_array][:product_sellable][0..2]
Now i'm more fun to talk to at dinner parties.
Similar problem with namespaces ruby savon and wsdl namespacing. I believe you have the same problem.
Additional Note: Try to use SOAP UI to debug, the generated XML from the WSDL and see the difference. Also change the XML to the XML generated from the code and validate the XML in SOAP UI. It will show the errors if any in SOAP UI, will make debugging faster and errors more understandable.
I believe your issue is a namespace problem. The wsVersion is within the shared object namespace "ins0". It is not in the "tns" namespace. Try changing your request to look like the following:
<env:Body>
<tns:GetProductSellableRequest>
<ins0:wsVersion>1.0.0</ins0:wsVersion>
</tns:GetProductSellableRequest>
</env:Body>

ruby savon and wsdl namespacing

I have an issue that I believe is in regards to namespaces. The WSDL can be downloaded from here: http://promostandards.org/content/wsdl/Order%20Shipment%20NotificationService/1.0.0/OSN-1-0-0.zip
When the request is generated it looks like this:
<soapenv:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.promostandards.org/WSDL/OrderShipmentNotificationService/1.0.0/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<tns:GetOrderShipmentNotificationRequest>
<tns:wsVersion>1.0.0</tns:wsVersion>
<tns:id>myusername</tns:id>
<tns:password>mypassword</tns:password>
<tns:queryType>3</tns:queryType>
<tns:shipmentDateTimeStamp>2017-07-19</tns:shipmentDateTimeStamp>
</tns:GetOrderShipmentNotificationRequest>
</soapenv:Body>
</soapenv:Envelope>
This results in a soap fault.
When SoapUI constructs the request using the same WSDL it looks like this
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.promostandards.org/WSDL/OrderShipmentNotificationService/1.0.0/" xmlns:shar="http://www.promostandards.org/WSDL/OrderShipmentNotificationService/1.0.0/SharedObjects/">
<soapenv:Header/>
<soapenv:Body>
<ns:GetOrderShipmentNotificationRequest>
<shar:wsVersion>1.0.0</shar:wsVersion>
<shar:id>myusername</shar:id>
<shar:password>mypassword</shar:password>
<ns:queryType>3</ns:queryType>
<ns:shipmentDateTimeStamp>2017-07-19</ns:shipmentDateTimeStamp>
</ns:GetOrderShipmentNotificationRequest>
</soapenv:Body>
</soapenv:Envelope>
You can see that SoapUI has placed the username and password inside the "shar" namespace. I noticed that this is not directly listed in the WSDL or in any XSD file directly loaded by the WSDL. It gets loaded something like WSDL => XSD file => XSD file containing shar namespace. could that be the issue? How can I add the namespace to just 3 of the keys? I'm using savon 2.11.1 and nori 2.6.0
Here is the solution I ended up using:
#client = Savon.client(
wsdl: 'OSN-1-0-0/WSDL/1.0.0/OrderShipmentNotificationService.wsdl',
endpoint: #endpoint,
env_namespace: :soapenv,
namespaces: { "xmlns:shar" => "http://www.promostandards.org/WSDL/OrderShipmentNotificationService/1.0.0/SharedObjects/" },
element_form_default: :qualified,
headers: { "accept-encoding" => "identity" }
)
response = #client.call(:get_order_shipment_notification, message: {
'shar:ws_version': #version,
'shar:id': #username,
'shar:password': #password,
query_type: 3,
shipment_date_time_stamp: date
})
I think Savon doesn't interpret linked XSD files, which are used here to reference the SharedObject. Had a similar problem and the only solution I found was to manually write the definition of the namespaces.
In your case it might look something like this:
client = Savon.client do
endpoint "http://localhost/OrderShipmentNotificationService.svc"
element_form_default :qualified
namespace "http://www.promostandards.org/WSDL/OrderShipmentNotificationService/1.0.0/"
namespace_identifier :ns
namespaces "xmlns:shar"=>"http://www.promostandards.org/WSDL/OrderShipmentNotificationService/1.0.0/SharedObjects/"
end
response = client.call("GetOrderShipmentNotificationRequest") do |locals|
locals.message "shar:wsVersion"=>"1.0.0","shar:id"=>"myusername",...
end

Passing Array Elements for Savon 2 (SOAP)

I'm trying to write code in Ruby with the Savon gem (v2) that fetches account information from a SOAP api, but I'm having an issue with passing an Array.
CampaignIds is supposed to be an array of integers.
Here is my code:
client = Savon.client(wsdl: "https://api7secure.publicaster.com/Pub7APIV1/Campaign.svc?singleWsdl")
message = {
"EncryptedAccountID" => api_key,
"APIPassword" => api_password,
"CampaignIds" => [3,4],
"StartDate" => yesterday,
"EndDate" => yesterday,
"IncludeTests" => false
}
client.call(:get_comparative_report_details_data, message: message)
which produces the following request:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ins0="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:tns="http://BlueSkyFactory.Publicaster7.Public.API" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<tns:GetComparativeReportDetailsData>
<tns:EncryptedAccountID>*****</tns:EncryptedAccountID>
<tns:APIPassword>*****</tns:APIPassword>
<tns:CampaignIds>3</tns:CampaignIds>
<tns:CampaignIds>4</tns:CampaignIds>
<tns:StartDate>2014-01-06</tns:StartDate>
<tns:EndDate>2014-01-06</tns:EndDate>
<tns:IncludeTests>false</tns:IncludeTests>
</tns:GetComparativeReportDetailsData>
</env:Body>
</env:Envelope>
whereas, if I play around in SOUP UI, the request should look like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:blu="http://BlueSkyFactory.Publicaster7.Public.API" xmlns:arr="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<soapenv:Header/>
<soapenv:Body>
<blu:GetComparativeReportData>
<blu:EncryptedAccountID>*****</blu:EncryptedAccountID>
<blu:APIPassword>*****</blu:APIPassword>
<blu:CampaignIds>
<arr:int>3</arr:int>
<arr:int>4</arr:int>
</blu:CampaignIds>
<blu:StartDate>2014-01-06T16:21:47-05:00</blu:StartDate>
<blu:EndDate>2014-01-07T16:21:47-05:00</blu:EndDate>
<blu:IncludeTests>false</blu:IncludeTests>
</blu:GetComparativeReportData>
</soapenv:Body>
</soapenv:Envelope>
Any Ideas?
You can try this syntax :
message = {
...
"CampaignIds" => {"int" => [3,4]},
...
}
That'll produce this output :
<CampaignIds>
<int>3</int>
<int>4</int>
</CampaignIds>
Hope this helps.
I just experienced the same issue and found a solution, that's not dependent on having a permissive SOAP endpoint. You can configure this behavior as a global using the unwrap key. This key is given as an option to Gyoku which generates the XML for Savon.
client = Savon.client(wsdl: 'https://example.com/wsdl', unwrap: true)
client.call(:cook_meal, message: { 'Ingredients' => ['tomato', 'basil', 'mozzarella'] })
Although the issue is old, better late than never.

How to call a SOAP Web Service using Ruby Savon?

I am trying to call a web service using Savon.
The request I am trying to generate is this (this is a valid request that is working, generated with wizdler):
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<FraudValidationRequest xmlns="http://schemas.gid.gap.com/fraudvalidation/v3">
<OrderHeader xmlns="">
<EntryType>1</EntryType>
.... more attributes
But I get something like this:
<?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:wsdl="http://schemas.gid.gap.com/fraudvalidation/v3"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<wsdl:validateOrder>
<fraudValidationRequest>
<orderHeader>
<entryType>1</entryType>
</orderHeader>
</fraudValidationRequest>
</wsdl:validateOrder>
</env:Body>
</env:Envelope>
So I get this error in the server side (the web service is implemented in java):
org.apache.axis2.databinding.ADBException: Unexpected subelement FraudValidationRequest
This is my client code in ruby:
require "savon"
URL = 'http://localhost:8080/MockFraudValidationServiceProvider/services/FraudValidationServiceV3'
begin
client = Savon.client do
# wsdl URL + "?wsdl"
endpoint URL
namespace "http://schemas.gid.gap.com/fraudvalidation/v3"
log_level :debug
pretty_print_xml :true
end
response = client.call(:validate_order,
message: {
FraudValidationRequest: { OrderHeader: { EntryType: 1 } }
}
)
puts response.to_hash;
end
I have tried several things: wsdl, endpoint and namespace, with/without namespace, camelcase or not, etc. but I can't generate the appropriate request.
I am not expert on SOAP (obviously), I understand that if there is a WSDL (my case) there is no need to set the namespace, but I am not sure. When I try using only WSDL I get this:
<?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:types="http://services.gid.gap.com/fraudvalidation/v3"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ins0="http://schemas.gid.gap.com/fraudvalidation/v3">
<env:Body>
<types:FraudValidationRequest>
<fraudValidationRequest>
<orderHeader>
<entryType>1</entryType>
</orderHeader>
</fraudValidationRequest>
</types:FraudValidationRequest>
</env:Body>
</env:Envelope>
Please advice, I hope I was clear.
Have you tried this?
require 'savon'
# create a client for the service
client = Savon.client(wsdl: 'http://service.example.com?wsdl')
p client.operations
# => [:find_user, :list_users]
# call the 'findUser' operation
response = client.call(:find_user, message: { id: 42 })
response.body
# => { find_user_response: { id: 42, name: 'Hoff' } }
client operations are the ones you can call, simply you can print them and check to call the right one.
message is a client parameter were you put your params, you can also set it this way:
params = {
:param_1 => "value",
_param_2 => 7
}
response = client.call(:find_user, message: params)
I use this code and I was able to call my Web Service

API Call With Savon SOAP Client Results In ContractFilter mismatch at the EndpointDispatcher Error

I've run into an issue where the Savon Ruby Gem generates a SOAP API call that fails, however when I copy and paste the exact same XML message into SOAP-UI it succeeds.
I send this message:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tem="http://tempuri.org/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:vis="http://schemas.datacontract.org/2004/07/Vision.SecureOriginCommand.ServiceContracts">
<soapenv:Body>
<tem:CameraConfiguration>
<tem:request>
<vis:ClientToken>5555</vis:ClientToken>
<vis:DeviceID>26219</vis:DeviceID>
<vis:Enabled>1</vis:Enabled>
<vis:Interval>60</vis:Interval>
</tem:request>
</tem:CameraConfiguration>
</soapenv:Body>
To this API (A remote web camera configuration):
https://oapqa.onasset.com/Services/SecureOriginCommand.svc?wsdl
But it fails with this message:
SOAP response (status 500):
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault><faultcode xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:ActionNotSupported</faultcode>
<faultstring xml:lang="en-US">The message with Action 'oapSetSentryReportingIntervalRequest' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None)</faultstring>
</s:Fault>
</s:Body>
My first thought was that I must have made a typo in the action name. But
no, when I try the exact same message in SOAP-UI I get the following
success:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<CameraConfigurationResponse xmlns="http://tempuri.org/">
<CameraConfigurationResult xmlns:a="http://schemas.datacontract.org/2004/07/Vision.SecureOriginCommand.ServiceContracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Error/>
<a:Result>true</a:Result>
</CameraConfigurationResult>
</CameraConfigurationResponse>
</s:Body>
</s:Envelope>
This leads me to believe that the issue is not being caused by the format
of my xml message but with the way I'm configuring my client. Here is the actual code:
Savon.configure do |config|
config.log = :debug
config.env_namespace = :soapenv
config.raise_errors = false
end
# TODO Enable ssl certficate verification
client = Savon::Client.new do
wsdl.document = TARGET_SO_WSDL
http.auth.ssl.verify_mode = :none
end
resp = client.request 'tem', 'CameraConfiguration' do
soap.namespaces['xmlns:vis'] = 'http://schemas.datacontract.org/2004/07/Vision.SecureOriginCommand.ServiceContracts'
soap.namespaces['xmlns:tem'] = 'http://tempuri.org/'
soap.body = {
'tem:request' => {
'vis:ClientToken' => ON_ASSET_API_KEY,
'vis:DeviceID' => webcam.gps_device.device_id,
'vis:Enabled' => 1,
'vis:Interval' => webcam.report_interval
}
}
end
I've spoken to the developer who maintains the API I'm trying to
access. I thought his response could provide a clue:
Binding on the RemoteSentryService was set to mexHttpBinding instead of mexHttpsBinding.
I don’t think this should give you a fault exception, because its working on .NET simulator client I have. And this endpoint is only used to generate the wsdl (MetaExchange Binding). But, given you are using a different client, I would still give it a shot.
I also regenerated the proxy from wsdl and updated my sample simulator and it looks good.
Is this issue a known issue with Savon and Microsoft SOAP
endpoints or HTTPS? Or is this issue something only I'm encountering?
Debugged it and noticed that Savon unfortunately doesn't send the correct SOAPAction HTTP header. FYI: After sending a SOAP request via soapUI, you can click on the "RAW" tab (vertically aligned on the request window) to investigate further.
Here's the complete example:
client = Savon::Client.new do
wsdl.document = TARGET_SO_WSDL
http.auth.ssl.verify_mode = :none
end
resp = client.request 'tem', 'CameraConfiguration' do
# Notice, that the SOAPAction needs to the wrapped in double quotes:
http.headers['SOAPAction'] = %("http://tempuri.org/ISecureOriginCommand/CameraConfiguration")
soap.namespaces['xmlns:vis'] = 'http://schemas.datacontract.org/2004/07/Vision.SecureOriginCommand.ServiceContracts'
soap.body = {
'tem:request' => {
'vis:ClientToken' => 5555,
'vis:DeviceID' => 26219,
'vis:Enabled' => 1,
'vis:Interval' => 60
}
}
end
Hope it works for you!

Resources