Getting Transaction Details From PayPal SOAP API (hopefully custom fields as well)
Asked Answered
G

2

7

I'm trying to get transaction details from PayPal's SOAP API but I'm running into into error from PayPal. It returns the error:

The transaction id is not valid

I know it's a valid transaction ID since I'm I'm able to get transaction details using the PayPal NVP API but maybe I have the SOAP request formatted incorrectly. I followed the PayPal SOAP API examples I can find across the web to construct the SOAP XML but they are slim. I'm using mac's PAW program to send a SOAP request to PayPal's API but this problem should be reproducible using an HTTP client.

I tried to use PayPal's REST API but there's no method to get transaction details (e.g. name, email, amount paid, custom fields) . I also tried to use the NVP (Name-Value-Pair) API and I do get back the transaction details but it doesn't give me all of the stored custom fields for a transaction. When I log in to PayPal, and view a single transaction, I can see all of the custom fields for that transaction, so I know they're being stored.

The SOAP API is my last hope.

Here's the SOAP envelope request I'm using:

 <?xml version="1.0" encoding="UTF-8"?>
 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="urn:ebay:api:PayPalAPI" xmlns:ebl="urn:ebay:apis:eBLBaseComponents" xmlns:cc="urn:ebay:apis:CoreComponentTypes" xmlns:ed="urn:ebay:apis:EnhancedDataTypes">
      <soapenv:Header>
           <ns:RequesterCredentials>
                <ebl:Credentials>
                     <ebl:Username>soap_api_username_here</ebl:Username>
                     <ebl:Password>soap_api_password_here</ebl:Password>
                     <ebl:Signature>soap_api_signature_here</ebl:Signature>
                </ebl:Credentials>
           </ns:RequesterCredentials>
      </soapenv:Header>
      <soapenv:Body>
           <ns:GetTransactionDetailsReq>
                <ns:GetTransactionDetailsRequest>
                     <ebl:Version>93.0</ebl:Version>
                     <ebl:TransactionID>8FX18476NR449891W</ebl:TransactionID>
                </ns:GetTransactionDetailsRequest>
           </ns:GetTransactionDetailsReq>
      </soapenv:Body>
 </soapenv:Envelope>

Here's the response I receive from the PayPal SOAP API:

    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:cc="urn:ebay:apis:CoreComponentTypes" xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext" xmlns:ed="urn:ebay:apis:EnhancedDataTypes" xmlns:ebl="urn:ebay:apis:eBLBaseComponents" xmlns:ns="urn:ebay:api:PayPalAPI">
      <SOAP-ENV:Header>
        <Security xmlns="http://schemas.xmlsoap.org/ws/2002/12/secext" xsi:type="wsse:SecurityType"/>
        <RequesterCredentials xmlns="urn:ebay:api:PayPalAPI" xsi:type="ebl:CustomSecurityHeaderType">
          <Credentials xmlns="urn:ebay:apis:eBLBaseComponents" xsi:type="ebl:UserIdPasswordType">
            <Username xsi:type="xs:string"/>
            <Password xsi:type="xs:string"/>
            <Signature xsi:type="xs:string"/>
            <Subject xsi:type="xs:string"/>
          </Credentials>
        </RequesterCredentials>
      </SOAP-ENV:Header>
      <SOAP-ENV:Body id="_0">
        <GetTransactionDetailsResponse xmlns="urn:ebay:api:PayPalAPI">
          <Timestamp xmlns="urn:ebay:apis:eBLBaseComponents">2016-08-02T16:43:02Z</Timestamp>
          <Ack xmlns="urn:ebay:apis:eBLBaseComponents">Failure</Ack>
          <CorrelationID xmlns="urn:ebay:apis:eBLBaseComponents">a464c181339f4</CorrelationID>
          <Errors xmlns="urn:ebay:apis:eBLBaseComponents" xsi:type="ebl:ErrorType">
            <ShortMessage xsi:type="xs:string">Transaction refused because of an invalid argument. See additional error messages for details.</ShortMessage>
            <LongMessage xsi:type="xs:string">The transaction id is not valid</LongMessage>
            <ErrorCode xsi:type="xs:token">10004</ErrorCode>
            <SeverityCode xmlns="urn:ebay:apis:eBLBaseComponents">Error</SeverityCode>
          </Errors>
          <Version xmlns="urn:ebay:apis:eBLBaseComponents">93.0</Version>
          <Build xmlns="urn:ebay:apis:eBLBaseComponents">000000</Build>
          <PaymentTransactionDetails xmlns="urn:ebay:apis:eBLBaseComponents" xsi:type="ebl:PaymentTransactionType">
            <ReceiverInfo xsi:type="ebl:ReceiverInfoType"/>
            <PayerInfo xsi:type="ebl:PayerInfoType">
              <PayerStatus xsi:type="ebl:PayPalUserStatusCodeType">verified</PayerStatus>
              <PayerName xsi:type="ebl:PersonNameType"/>
              <Address xsi:type="ebl:AddressType">
                <AddressOwner xsi:type="ebl:AddressOwnerCodeType">PayPal</AddressOwner>
                <AddressStatus xsi:type="ebl:AddressStatusCodeType">None</AddressStatus>
              </Address>
            </PayerInfo>
            <PaymentInfo xsi:type="ebl:PaymentInfoType">
              <TransactionType xsi:type="ebl:PaymentTransactionCodeType">none</TransactionType>
              <PaymentType xsi:type="ebl:PaymentCodeType">none</PaymentType>
              <PaymentStatus xsi:type="ebl:PaymentStatusCodeType">None</PaymentStatus>
              <PendingReason xsi:type="ebl:PendingStatusCodeType">none</PendingReason>
              <ReasonCode xsi:type="ebl:ReversalReasonCodeType">none</ReasonCode>
            </PaymentInfo>
            <PaymentItemInfo xsi:type="ebl:PaymentItemInfoType">
              <Subscription xsi:type="ebl:SubscriptionInfoType"/>
              <Auction xsi:type="ebl:AuctionInfoType"/>
            </PaymentItemInfo>
          </PaymentTransactionDetails>
        </GetTransactionDetailsResponse>
      </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>

I'm not sure what I'm doing wrong but maybe someone with more experience can spot the error easier than I can. I responded to another user's question about the PayPal REST API and getting transaction details from that but as far as I know, there's no way to do that Get customer details after transaction . If you have found a way to accomplish this with the REST API, let me know cause I would much rather use REST than SOAP.

Thanks.

Gourley answered 2/8, 2016 at 17:23 Comment(2)
What is your server side language that you are using to send receive? I'm using asp.net, but pretty sure it ain't using XML.Chowchow
@Chowchow I was planning to use PHP to make the call to the PayPal SOAP API but if I can't get it to work with Paw or Postman, I doubt the the PHP call would work and would just further confuse me. If you're using the PayPal SOAP API, then you're ASP.net program is compiling an XML call to send to the PayPal SOAP API.Gourley
S
1

The error message is a red herring. PayPal can't find any TransactionId, reporting the empty TransactionId as invalid.

The TransactionId element belongs to the urn:ebay:api:PayPalAPI namespace. Your XML attaches it to the urn:ebay:apis:eBLBaseComponents namespace. All you need to do is change the ebl:TransactionId to ns:TransactionId.

 <?xml version="1.0" encoding="UTF-8"?>
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="urn:ebay:api:PayPalAPI" xmlns:ebl="urn:ebay:apis:eBLBaseComponents" xmlns:cc="urn:ebay:apis:CoreComponentTypes" xmlns:ed="urn:ebay:apis:EnhancedDataTypes">
  <soapenv:Header>
       <ns:RequesterCredentials>
            <ebl:Credentials>
                 <ebl:Username>soap_api_username_here</ebl:Username>
                 <ebl:Password>soap_api_password_here</ebl:Password>
                 <ebl:Signature>soap_api_signature_here</ebl:Signature>
            </ebl:Credentials>
       </ns:RequesterCredentials>
  </soapenv:Header>
  <soapenv:Body>
      <ns:GetTransactionDetailsReq>
           <ns:GetTransactionDetailsRequest>
                <ebl:Version>204.0</ebl:Version>
                <ns:TransactionID>8FX18476NR449891W</ns:TransactionID>
           </ns:GetTransactionDetailsRequest>
      </ns:GetTransactionDetailsReq>
 </soapenv:Body>

Check this example at the PayPal KB.

Seamark answered 9/8, 2016 at 15:42 Comment(1)
this works. It looks like PayPal's SOAP API will still only retrieve two of the possible seven options it can store. This is a known problem with the NVP and SOAP API #16764686Gourley
C
0

I would have put this as a comment but it is pretty full of goobly gook. At the expense of being way off I might be of some help maybe. So my vb.net code sends a form to paypal which includes "notify_url".

            ' determining the URL to work with depending on whether sandbox or a real PayPal account should be used
            If strRealOrSand = "Sand" Then
                URL = "https://www.sandbox.paypal.com/cgi-bin/webscr"
                business = "[email protected]"  ' AppSettings("BusinessEmail")  (sandbox account business email)
            ElseIf strRealOrSand = "Real" Then
                URL = "https://www.paypal.com/cgi-bin/webscr"
                business = "[email protected]"    ' AppSettings("BusinessEmail")  (real pay pal account account business email)
            End If

notify_url = "http://www.xxxxx.com/accounts/done.aspx"  



    <form id="payForm" method="post" action="<%Response.Write (URL)%>" >
        <input type="hidden" name="cmd" value="<%Response.Write (cmd)%>" />
        <input type="hidden" name="business" value="<%Response.Write (business)%>" />
        <input type="hidden" name="item_name" value="<%Response.Write (item_name)%>" />
        <input type="hidden" name="amount" value="<%Response.Write (amount)%>" />
        <input type="hidden" name="no_shipping" value="<%Response.Write (no_shipping)%>" />
        <input type="hidden" name="return" value="<%Response.Write (return_url)%>" />
        <input type="hidden" name="rm" value="<%Response.Write (rm)%>" />
        <input type="hidden" name="notify_url" value="<%Response.Write (notify_url)%>" />
        <input type="hidden" name="cancel_return" value="<%Response.Write (cancel_url)%>" />
        <input type="hidden" name="currency_code" value="<%Response.Write (currency_code)%>" />
        <input type="hidden" name="custom" value="<%Response.Write (row_id)%>" />
    </form>

    <script type="text/javascript">
        document.forms["payForm"].submit ();
    </script>

</body>

Then in my "notify_url" page load it gets what PayPal sends back after transaction completes. You'll notice there is a ton of debug emails being sent back to me. This was my doing.

   Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim vReceived As String = ""
        Dim vFormValues As String = ""
        Dim vResponder As String = ""
        Dim strE As String = ""
        Dim intAccountID As Integer = 0
        Dim intCreditsPurchased As Integer = 0

        Dim vWebRequest As System.Net.HttpWebRequest
        Dim vSSend As Boolean = False
        'vWebRequest = CType(System.Net.WebRequest.Create("https://www.sandbox.paypal.com/cgi-bin/webscr"), System.Net.HttpWebRequest)
        vWebRequest = CType(System.Net.WebRequest.Create("https://www.paypal.com/cgi-bin/webscr"), System.Net.HttpWebRequest)



        vWebRequest.Method = "POST"
        vWebRequest.ServicePoint.Expect100Continue = False
        vWebRequest.ContentType = "application/x-www-form-urlencoded"



        Try
            vFormValues = Encoding.ASCII.GetString(Request.BinaryRead(Request.ContentLength))
            vReceived = "cmd=_notify-validate&" & vFormValues
        Catch ex As Exception
            sSend_Mail_From_done_aspx("Requested Form.ToString", ex.ToString)
        End Try

        vWebRequest.ContentLength = vReceived.Length
        Dim vStreamOut As System.IO.StreamWriter = New System.IO.StreamWriter(vWebRequest.GetRequestStream(), Encoding.ASCII)
        vStreamOut.Write(vReceived)
        vStreamOut.Close()
        Dim vStreamIn As New System.IO.StreamReader(vWebRequest.GetResponse().GetResponseStream())
        vResponder = vStreamIn.ReadToEnd()
        vStreamIn.Close()



        Dim vFieldName As String
        Dim vFieldValue As String = ""
        Dim vFields As New Collection

        For Each vFieldName In Request.Form
            'strE = strE & Request.Form.Item(vFieldName) & " "
            strE &= vFieldName & ": " & Request.Form.Item(vFieldName) & vbCrLf
            'vFieldValue = Request.Form.Item(vFieldName)
            'vFields.Add(Decode(vFieldValue), Decode(vFieldName).ToLower)
        Next

        sSend_Mail_From_done_aspx("BEFORE VERIFIED CHECK, WHAT vResponder CONTAINS", strE)


        Dim transactionID As String = ""
        Dim dblAmount As Double
        Dim intRowID As Integer
        Dim dblPayPalFee As Double

        Dim strMemo As String = ""
        Dim strPayerEmail As String = ""
        Dim strPaymentDate As String = ""

        If Trim(vResponder).ToUpper = "VERIFIED" Then

            For Each vFieldName In Request.Form
                strE &= vFieldName & ": " & Request.Form.Item(vFieldName) & vbCrLf

            Next

            sSend_Mail_From_done_aspx("VERIFIED CAME THROUGH", strE)

            Try
                transactionID = Request.Form.Item("txn_id").ToString()
                dblAmount = CType(Request.Form.Item("payment_gross"), Double)
                intRowID = CType(Request.Form.Item("custom"), Integer)
                dblPayPalFee = CType(Request.Form.Item("payment_fee"), Double)
                If Len(Request.Form.Item("memo") & "") <> 0 Then
                    strMemo = Request.Form.Item("memo").ToString.Replace("'", "")
                End If
                strPayerEmail = Request.Form.Item("payer_email").ToString
                strPaymentDate = Request.Form.Item("payment_date").ToString


            Catch ex As Exception
                sSend_Mail_From_done_aspx("Request.QueryString)", ex.ToString)
            End Try


            Try

                '==============================
                'SAVE TRANSACTION INFO HERE
                '==============================
                Dim sb As New StringBuilder
                sb.Append("UPDATE dbo.tblTransactions ")
                sb.Append("SET pp_txn_id='" & transactionID & "'")
                sb.Append(", pp_payment_gross=" & dblAmount)
                sb.Append(", pp_mc_fee=" & dblPayPalFee)
                sb.Append(", memo='" & strMemo & "'")
                sb.Append(", pp_payer_email='" & strPayerEmail & "'")
                sb.Append(", pp_payment_date='" & strPaymentDate & "'")
                sb.Append(" WHERE RowID =" & intRowID)

                'SEND SQL TO DEVELOPER
                sSend_Mail_From_done_aspx("INSERT statement BEFORE action", sb.ToString)

                Dim conn As New SqlConnection(f1.fUseThisConnection(Server.MachineName))
                Dim cmd As New SqlCommand(sb.ToString, conn)

                cmd.Connection.Open()
                cmd.ExecuteNonQuery()

                '=========================================================
                'UPDATE ACCOUNT INFO HERE (ADD CREDITS TO CURRENT AMOUNT)
                '=========================================================
                Dim dr As System.Data.SqlClient.SqlDataReader


                sb.Length = 0
                'GET ACCOUNT ID, AND CreditsPurchased
                sb.Append("SELECT AccountID, CreditsPurchased FROM dbo.tblTransactions ")
                sb.Append(" WHERE RowID =" & intRowID)

                cmd.CommandText = sb.ToString
                dr = cmd.ExecuteReader()

                If dr.Read() Then

                    intAccountID = dr("AccountID")
                    intCreditsPurchased = dr("CreditsPurchased")


                End If

                dr.Close()


                sb.Length = 0

                'AT 1.10 A CREDIT, WE DIVIDE THE AMOUNT PAYPAY CHARGES BY THIS TO GET CREDITS PURCHASED

                sb.Append("UPDATE dbo.tblAL SET Credits = Credits + " & intCreditsPurchased)
                sb.Append(" WHERE AccountID =" & intAccountID)

                cmd.CommandText = sb.ToString
                cmd.ExecuteNonQuery()

                'SEND ACCOUNT UPDATE AMOUNT TO DEVELOPER
                sSend_Mail_From_done_aspx(intCreditsPurchased & " CREDITS ADDED TO ", sb.ToString)

                cmd.Dispose()
                conn.Close()
                conn = Nothing

                MySession.Credits = intCreditsPurchased


            Catch ex As Exception
                sSend_Mail_From_done_aspx("tblTransactions NOT UPDATED with Transaction Info", ex.ToString())
            End Try

        Else
            sSend_Mail_From_done_aspx(Trim(vResponder).ToUpper, "TRANSACTION NOT VERIFIED")

        End If
    End Sub

I think the request/responses are these below:

submitted form

URL = "https://www.paypal.com/cgi-bin/webscr"

sends back to this inside the "notify_url" that is submitted

Dim vWebRequest As System.Net.HttpWebRequest
            Dim vSSend As Boolean = False
            'vWebRequest = CType(System.Net.WebRequest.Create("https://www.sandbox.paypal.com/cgi-bin/webscr"), System.Net.HttpWebRequest)
            vWebRequest = CType(System.Net.WebRequest.Create("https://www.paypal.com/cgi-bin/webscr"), System.Net.HttpWebRequest)

Sure would be nice to have a "PayPalFiddle" haha

Chowchow answered 9/8, 2016 at 4:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.