2

Can anyone spot what may be incorrect in the below SOAP request?

I am receiving a 400 response, "Bad Request", with the below SOAP request. After chatting with support and looking at documentation, I can't isolate what is the issue. For my use-case, I cannot utilize the SDK

I have tried passing my variables through explicitly as well as changing up my headers (no luck).

I utilized a sample request from Postman as my base, URL below: https://www.postman.com/salesforce-developers/workspace/salesforce-developers/request/14448118-3f18faee-ead6-4351-81ab-e48deba93dd3

I'm using python 3.7+ in Jupyter on Windows

url_ = f'https://{subdomain}.soap.marketingcloudapis.com/Service.asmx'

soap_payload = '''
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
        <a:Action s:mustUnderstand="1">Retrieve</a:Action>
        <a:To s:mustUnderstand="1">https://{subdomain}.soap.marketingcloudapis.com/Service.asmx</a:To>
        <fueloauth xmlns="http://exacttarget.com">{token}</fueloauth>
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <RetrieveRequestMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">
            <RetrieveRequest>
                <ObjectType>DataExtension</ObjectType>
                <Properties>ObjectID</Properties>
                <Properties>CustomerKey</Properties>
                <Properties>Name</Properties>
            </RetrieveRequest>
        </RetrieveRequestMsg>
    </s:Body>
</s:Envelope>
'''


headers = {'Content-Type': 'text/xml'}

soap_response = requests.post(url_,data=soap_payload.format(subdomain=subdomain, token=token), headers=headers)

print(soap_response)
print(soap_response.text)

Below Is How I Was Generating My Token To Pass To The SOAP Packet (Which has been working):

payload = {
    'client_id': clientid,
    'client_secret': clientsecret,
    'grant_type': 'client_credentials'
}


 r = requests.post(auth_base_url,data=payload)

 body = json.loads(r.content)
 token = body['access_token']
1
  • Did you start with the Python code generated by Postman in the Code tab -- the </> icon? Nov 5, 2022 at 13:41

1 Answer 1

1

Give this a try:

url_ = f'https://{subdomain}.soap.marketingcloudapis.com/Service.asmx'

soap_payload = \
"""
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
        <fueloauth xmlns="http://exacttarget.com">{0}</fueloauth>
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <RetrieveRequestMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">
            <RetrieveRequest>
                <ObjectType>DataExtension</ObjectType>
                <Properties>CustomerKey</Properties>
                <Properties>Name</Properties>
                <Properties>ObjectID</Properties>
            </RetrieveRequest>
        </RetrieveRequestMsg>
    </s:Body>
</s:Envelope>
"""
soap_payload = soap_payload.format(token)

headers = {
'Content-Type': 'text/plain',
'SOAPAction': 'Retrieve'
}

soap_response = requests.request("POST", url_, headers=headers, data=soap_payload)

print(soap_response)
print(soap_response.text)

Here's a SOAP GetSystemStatus function I wrote in Python. Perhaps you can retrofit it for your SOAP use case if you can't get the above functioning:

def GetSystemStatus(authEndpoint: str, clientId: str, clientSecret: str, mid:str):

  accessToken = getToken(authEndpoint, clientId, clientSecret, mid)
  url = soapEndpoint + "/Service.asmx"

  payload = \
  """
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:par="http://exacttarget.com/wsdl/partnerAPI">
      <soapenv:Header>
          <fueloauth xmlns="http://exacttarget.com">{0}</fueloauth>
      </soapenv:Header>
      <soapenv:Body>
          <par:SystemStatusRequestMsg/>
      </soapenv:Body>
  </soapenv:Envelope>
  """
  payload = payload.format(accessToken)

  headerVals = {
    'Content-Type': 'text/xml',
    'SOAPAction': 'GetSystemStatus'
  }

  response = requests.request("POST", url, headers=headerVals, data=payload)

  # must specify encoding in order to parse
  utf8_parser = etree.XMLParser(encoding='utf-8')
  responseXML = etree.fromstring(response.text.encode('utf-8'), parser=utf8_parser)

  # the . in the XPATH indicates a context item, double-slash indicates relative path anywhere
  # namespaces are required if used in response, {*} means any namespace
  StatusCode =  responseXML.find(".//{*}Result/{*}StatusCode").text
  StatusMessage = responseXML.find(".//{*}Result/{*}StatusMessage").text
  SystemStatus = responseXML.find(".//{*}Result/{*}SystemStatus").text
  OverallStatus = responseXML.find(".//{*}OverallStatus").text

  return OverallStatus

Here's the getToken function that goes along with it:

def getToken(authEndpoint: str, clientId: str, clientSecret: str, mid: str):

  token = None

  payload = {
        "grant_type": "client_credentials",
        "client_id": clientId,
        "client_secret": clientSecret,
        "account_id": mid
  }

  response = requests.post(authEndpoint + "/v2/token", data=payload)
  response.raise_for_status()
  token = json.loads(response.text)["access_token"]
  return token

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .