Transaction Details Request


PayPal's API can be used to obtain additional information on previous transactions; I've found this feature to be most useful because you can use the transaction ID given to the merchant or to the client. As such, this system can be used to locate a payment based on the information a client has been given (as is usually the case for a customer service agent).

Note 

Remember for the average transaction where a customer purchases a product and pays PayPal via a credit card, three transaction IDs are issued: two to the client (one for the payment to the merchant, another for the transfer of funds from the credit card to the PayPal account), and one to the merchant (for the transfer of funds from the client). As the merchant, you only receive that one transaction ID, so to deal with a customer enquiry, you will need to search under a transaction ID they received, a function this interface provides. You will, however, need to ensure that the customers give you the transaction ID for the payment, not for the transfer of funds from their bank or credit card.

With this API, you return to the traditional method of your code contacting the server and parsing the response. However, unlike the majority of previous examples, NuSOAP will not be used. Unfortunately, NuSoap does not yet allow for the inclusion of a client certificate with a secure request. As such, cURL will be used. cURL is really the Swiss Army knife of Net transactions: It facilitates communications over http, https, ftp, ftps, telnet, gopher, and so on. Most importantly, it allows for the use of client-side certificates to authenticate when communicating over a secure protocol (which is what PayPal requires). CURL only provides the transport medium for the request; it is up to you to generate the request. Because the requests are pretty static (and have already ruled out NuSOAP), I have elected to generate the request by hand, and substitute the transaction ID as required.

This next function has two main steps. First, it generates the SOAP query to be sent to PayPal. Notice the use of the Heredoc syntax to encapsulate the SOAP request. This saves a lot of escaping, and still allows for variable replacement when it comes to the transaction ID. Next, the CURL object is initialized and configured to take care of the transaction itself.

Note 

Just in case you're not familiar with it, the Heredoc syntax allows you to quote a segment of text using your own string to start and end the quote. This allows you to quote a lot of other quotes without needing to worry about escaping anything. The format is shown below in the following code. It's basically three open braces followed by your own string, then after the quoted block, on its own line, the same variable again to close it. There is a big warning on the PHP documentation page that introduces the Heredoc syntax, but it's worth repeating. You absolutely cannot stick anything else on the line that ends the quoted block, particularly a tab character. The ending tag must be at the start of the line, and can be followed by a semicolon. That's it — no spaces, no tabs, no white space, nothing.

 function transLookUp($transid) {   $username = "stb_api1.preinheimer.com";   $password = "ZJXaRwTBoL8m";   $request = <<< End_Of_Quote <SOAP-ENV:Envelope   xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"   xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"   xmlns:xsd="http://www.w3.org/1999/XMLSchema"   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">   <SOAP-ENV:Header>     <RequesterCredentials xmlns="urn:ebay:api:PayPalAPI"       SOAP-ENV:mustUnderstand="1">       <Credentials xmlns="urn:ebay:apis:eBLBaseComponents">         <Username>$username</Username>         <Password>$password</Password>         <Subject/>       </Credentials>     </RequesterCredentials>   </SOAP-ENV:Header> 

Here the header for the SOAP request is defined. The RequesterCredentials section identifies the account the request is associated with, and the username and password are defined by PayPal and are different from your PayPal login account information. The Subject field is only needed if the transaction is being completed by one party on behalf of another (for example, if all of the PayPal API work was outsourced to another firm, they would log in with their credentials, not the account holders). The Subject line would indicate the account the transaction should be completed against. For more information, see the Order Management Integration Guide available within the PayPal development site.

   <SOAP-ENV:Body>     <GetTransactionDetailsReq xmlns="urn:ebay:api:PayPalAPI">       <GetTransactionDetailsRequest         xsi:type="ns:GetTransactionDetailsRequestType">         <Version xmlns="urn:ebay:apis:eBLBaseComponents"           xsi:type="xsd:string">1.0</Version>         <TransactionID xsi:type="ebl:TransactionId">$transid</TransactionID>       </GetTransactionDetailsRequest>     </GetTransactionDetailsReq>   </SOAP-ENV:Body> </SOAP-ENV:Envelope> End_Of_Quote; 

The body of the request contains the request itself. The structure here (and in the header) is explicitly defined by PayPal, and relatively easy to follow. The only two parameters being passed are the version of the API call (1.0 in this case) and the transaction ID being enquired about.

   $ch = curl_init();   curl_setopt($ch, CURLOPT_URL, "https://api.sandbox.paypal.com/2.0/");   curl_setopt($ch, CURLOPT_SSLCERT, "../certs/cert_key_pem-1.txt");   curl_setopt($ch, CURLOPT_POST, TRUE);   curl_setopt($ch, CURLOPT_POSTFIELDS, $request);   curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 

The CURL object is created and configured. The CURLOPT_URL parameter defines the URL that the call should be made against. CURLOPT_SSLCERT declares the location on disk where the client certificate (provided by PayPal) is located. This client certificate is provided by PayPal and further authenticates you as an authorized user when making calls to the PayPal API. The certificate must not be stored within the document root. Not only does this allow anyone with some creativity and a web browser to crack half of the API security scheme, but it will also result in an army of security gnomes invading your house and forcing you to write "I will not store security certificates within the document root" on a blackboard 1,000 times. Just don't do it — store the certificate in a separate directory readable only by your web server. The CURLOPT_POST parameter defines this as a POST request, as opposed to a GET request. The CURLOPT_POSTFIELDS parameter sends along the SOAP request generated earlier. Finally, the CURLOPT_RETURNTRANSFER parameter instructs CURL to return the output of the request, rather than sending it directly to the end user.

   $response = curl_exec($ch);   if (curl_error($ch))  {    file_put_contents("/tmp/curl_error_log.txt", curl_errno($ch) . ": ".     curl_error($ch), "a+");    curl_close($ch);    return null;  }else  {     curl_close($ch);     $xml = simplexml_load_string($response);     return $xml;  } } 

CURL sends all of its output directly to the browser, which isn't exactly what you are hoping for, so output buffering is started to record PayPal's response. The request itself is executed with the cURL_exec() call, and the response is stuck appropriately enough into the $response variable. If CURL encounters an error, null is returned, and the error is recorded to a log file for later examination. If all goes well, the connection is closed. The response is turned into a SimpleXML object, and returned for use.

PayPal's Response

Completely unlike the brief request, the response is quite expansive. I have trimmed the initial namespace declarations to save space, but other than that this is the full response:

 <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope  ..  xmlns:ns="urn:ebay:api:PayPalAPI">  <SOAP-ENV:Header>   <Security xmlns="http://schemas.xmlsoap.org/ws/2002/12/secext"     xsi:type="wsse:SecurityType"></Security>   <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"></Username>    <Password xsi:type="xs:string"></Password>    <Subject xsi:type="xs:string"></Subject></Credentials>   </RequesterCredentials>  </SOAP-ENV:Header>  <SOAP-ENV:Body >   <GetTransactionDetailsResponse xmlns="urn:ebay:api:PayPalAPI">    <Timestamp xmlns="urn:ebay:apis:eBLBaseComponents">2005-04-15T02:53:24Z     </Timestamp>    <Ack xmlns="urn:ebay:apis:eBLBaseComponents">Success</Ack>    <Version xmlns="urn:ebay:apis:eBLBaseComponents">1.000000</Version>    <Build xmlns="urn:ebay:apis:eBLBaseComponents">1.0006</Build>    <PaymentTransactionDetails xmlns="urn:ebay:apis:eBLBaseComponents"     xsi:type="ebl:PaymentTransactionType">     <ReceiverInfo xsi:type="ebl:ReceiverInfoType">      <Business xsi:type="ebl:EmailAddressType">stb@preinheimer.com</Business>      <Receiver xsi:type="ebl:EmailAddressType">stb@preinheimer.com</Receiver>       <ReceiverID xsi:type="ebl:UserIDType">L3D7XTLLRU82J</ReceiverID>      </ReceiverInfo>     <PayerInfo xsi:type="ebl:PayerInfoType">      <Payer xsi:type="ebl:EmailAddressType">bigbird@example.com</Payer>       <PayerID xsi:type="ebl:UserIDType">JUVP4APFFAQZU</PayerID>       <PayerStatus xsi:type="ebl:PayPalUserStatusCodeType">unverified        </PayerStatus>       <PayerName xsi:type="ebl:PersonNameType">        <FirstName xmlns="urn:ebay:apis:eBLBaseComponents">Big</FirstName>        <LastName xmlns="urn:ebay:apis:eBLBaseComponents">Bird</LastName>       </PayerName>       <PayerBusiness xsi:type="xs:string"></PayerBusiness>       <Address xsi:type="ebl:AddressType">        <Name xsi:type="xs:string">Big Bird</Name>        <Street1 xsi:type="xs:string">123 Seasame St</Street1>        <Street2 xsi:type="xs:string"></Street2>        <CityName xsi:type="xs:string">CaringVille</CityName>        <StateOrProvince xsi:type="xs:string">Ontario</StateOrProvince>        <Country xsi:type="ebl:CountryCodeType">CA</Country>        <CountryName>Canada</CountryName>        <PostalCode xsi:type="xs:string">N1K 1K9</PostalCode>        <AddressOwner xsi:type="ebl:AddressOwnerCodeType">PayPal</AddressOwner>        <AddressStatus xsi:type="ebl:AddressStatusCodeType">Confirmed          </AddressStatus>       </Address>      </PayerInfo>      <PaymentInfo xsi:type="ebl:PaymentInfoType">       <TransactionID>8N604562NC480291D</TransactionID>       <ParentTransactionID xsi:type="ebl:TransactionId"></ParentTransactionID>       <ReceiptID></ReceiptID>       <TransactionType xsi:type="ebl:PaymentTransactionCodeType">web-accept        </TransactionType>       <PaymentType xsi:type="ebl:PaymentCodeType">instant</PaymentType>       <PaymentDate xsi:type="xs:dateTime">2005-04-15T02:48:34Z</PaymentDate>       <GrossAmount xsi:type="cc:BasicAmountType" currency>29.95        </GrossAmount>       <FeeAmount xsi:type="cc:BasicAmountType" currency>1.47</FeeAmount>       <TaxAmount xsi:type="cc:BasicAmountType" currency>0.00</TaxAmount>       <ExchangeRate xsi:type="xs:string"></ExchangeRate>      <PaymentStatus xsi:type="ebl:PaymentStatusCodeType">Completed       </PaymentStatus>      <PendingReason xsi:type="ebl:PendingStatusCodeType">none</PendingReason>      <ReasonCode xsi:type="ebl:ReversalReasonCodeType">none</ReasonCode>     </PaymentInfo>     <PaymentItemInfo xsi:type="ebl:PaymentItemInfoType">      <InvoiceID xsi:type="xs:string"></InvoiceID>      <Custom xsi:type="xs:string"></Custom>      <Memo xsi:type="xs:string"></Memo>      <SalesTax xsi:type="xs:string">0.00</SalesTax>      <PaymentItem xmlns="urn:ebay:apis:eBLBaseComponents"       xsi:type="ebl:PaymentItemType">       <Name xsi:type="xs:string">Professional Web APIs with PHP</Name>       <Number xsi:type="xs:string">0764589547</Number>       <Quantity xsi:type="xs:string">1</Quantity>       <SalesTax xsi:type="xs:string"></SalesTax>      </PaymentItem>      <Subscription xsi:type="ebl:SubscriptionInfoType" recurring=""       reattempt="">       <SubscriptionID></SubscriptionID>       <Username xsi:type="xs:string"></Username>       <Password xsi:type="xs:string"></Password>       <Recurrences xsi:type="xs:string"></Recurrences>      </Subscription>      <Auction xsi:type="ebl:AuctionInfoType" multiItem="">       <BuyerID xsi:type="xs:string"></BuyerID>      </Auction>     </PaymentItemInfo>    </PaymentTransactionDetails>   </GetTransactionDetailsResponse>  </SOAP-ENV:Body> </SOAP-ENV:Envelope> 

As you can tell, pretty much anything you need to know about the request, and a whole lot you don't, is available via the GetTransactionDetails API call. How you use the data available depends entirely on your implementation. Common uses would be to check on PaymentStatus following a customer enquiry, or using the full information to reprocess transactions that were lost due to an IPN failure.

The SimpleXML object returned contains the entire response. However, because of the namespacing used in SOAP responses, and the way SimpleXML handles those namespaces, accessing it can be a little bit tricky. The easiest way to access information nested within namespaced elements is to use SimpleXML's xpath() function:

 $soapBody = $xml->xpath(‘/SOAP-ENV:Envelope/SOAP-ENV:Body'); 

Xpath searches the SimpleXML object for the specified tree, because depending on what type of search you run, multiple results are possible. The result is always given as an array, regardless of the number of results returned. Because only the data within the GetTransactionDetailsResponse tree are relevant for future processing, you can further trim the tree to contain only that information:

 $body = $soapBody[0]->GetTransactionDetailsResponse; 

Using this new body object, you can access all of the information within the response with relative ease:

 $timestamp = $body->Timestamp; $payerEmail = $body->PaymentTransactionDetails->PayerInfo->Payer; $paymentStatus = $body->PaymentTransactionDetails->PaymentInfo->PaymentStatus; 

Here the timestamp, payer's email, and payment status are copied into their own variables for possible use later. To access any particular element within the response, start with the name of the element you want on the right-hand side, and work toward the GetTransactionDetailsResponse branch, recording each parent you pass through along the way.

Sending a Refund

Unfortunately, at some point you are probably going to need to issue a refund to a customer for whatever reason. The code to send a refund is very similar to the previous example:

 function refund($transid) {   $username = "stb_api1.preinheimer.com";   $password = "ZJXaRwTBoL8m";     $request = <<< End_Of_Quote <SOAP-ENV:Envelope   xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"   xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"   xmlns:xsd="http://www.w3.org/1999/XMLSchema"   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">   <SOAP-ENV:Header>     <RequesterCredentials xmlns="urn:ebay:api:PayPalAPI"       SOAP-ENV:mustUnderstand="1">       <Credentials xmlns="urn:ebay:apis:eBLBaseComponents">         <Username>$username</Username>         <Password>$password</Password>         <Subject/>       </Credentials>     </RequesterCredentials>   </SOAP-ENV:Header>   <SOAP-ENV:Body>     <RefundTransactionReq xmlns="urn:ebay:api:PayPalAPI">       <RefundTransactionRequest         xsi:type="ns:RefundTransactionRequestType">         <Version xmlns="urn:ebay:apis:eBLBaseComponents"           xsi:type="xsd:string">1.0</Version>         <TransactionID xsi:type="ebl:TransactionId">$transid</TransactionID>         <RefundType>Full</RefundType>       </RefundTransactionRequest>     </RefundTransactionReq>   </SOAP-ENV:Body> </SOAP-ENV:Envelope> End_Of_Quote;   $ch = curl_init();   curl_setopt($ch, CURLOPT_URL, "https://api.sandbox.paypal.com/2.0/");   curl_setopt($ch, CURLOPT_SSLCERT, "./cert_key_pem-1.txt");   curl_setopt($ch, CURLOPT_POST, TRUE);   curl_setopt($ch, CURLOPT_POSTFIELDS, $request);   ob_start();   curl_exec($ch);   $response = ob_get_clean();    echo $response;   if (curl_error($ch)) .{    file_put_contents("/tmp/curl_error_log.txt", curl_errno($ch) . ": ".       curl_error($ch), "a+");    curl_close($ch);    return null;  }else  {    curl_close($ch);     $xml = simplexml_load_string($response);     return $xml;  } } 

The body of the request differs because you are performing a different API call. However, the function itself, as well as the structure of the SOAP request, remains identical. Fortunately, the request for a refund transaction is much shorter (I have again cut out the namespace declarations for the sake of brevity):

 <?xml version="1.0" encoding=" UTF-8"?> <SOAP-ENV:Envelope   ...   xmlns:ns="urn:ebay:api:PayPalAPI">   <SOAP-ENV:Header>     <Security xmlns="http://schemas.xmlsoap.org/ws/2002/12/secext"       xsi:type="wsse:SecurityType"></Security>     <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"></Username>         <Password xsi:type="xs:string"></Password>         <Subject xsi:type="xs:string"></Subject>       </Credentials>     </RequesterCredentials>   </SOAP-ENV:Header>   <SOAP-ENV:Body >     <RefundTransactionResponse xmlns="urn:ebay:api:PayPalAPI">       <Timestamp xmlns="urn:ebay:apis:eBLBaseComponents">2005-04-15T04:05:17Z         </Timestamp>       <Ack xmlns="urn:ebay:apis:eBLBaseComponents">Success</Ack>       <Version xmlns="urn:ebay:apis:eBLBaseComponents">1.000000</Version>       <Build xmlns="urn:ebay:apis:eBLBaseComponents">1.0006</Build>     </RefundTransactionResponse>   </SOAP-ENV:Body> </SOAP-ENV:Envelope> 

The key element is the Ack element within the body, which reports the Success of the transaction. Using code similar to the previous example, you can access that element:

 $soapBody = $xml->xpath(‘/SOAP-ENV:Envelope/SOAP-ENV:Body'); $body = $soapBody[0]->RefundTransactionResponse; $success = $body->Ack; 

Note 

Note that with PayPal, a merchant has 60 days to perform a refund on any transaction. During that time frame, PayPal only deducts the amount you actually received from your account, and refunds the transaction fee itself. If you need to issue a refund after the 60-day mark, you will instead need to issue a new payment for the full amount.

Improving the Code, a Modular Approach

The previous two examples were functionally identical, with only a few minor changes to a string to separate them. By examining the similarities and differences between the two SOAP calls, a modular function that can be used with both these API calls (and others to be covered later) can be written.

This function will take two parameters, the first being the name of the API call in question (to be inserted into the request body), and the second being an array of values containing the name, type, and value for all the required parameters, as in paypal_api.php:

 function makeAPICall($specificAPIName, $APIParameters) { $username = "stb_api1.preinheimer.com"; $password = "ZJXaRwTBoL8m"; $parameterList = ""; foreach ($APIParameters as $parameter) {   $parameterList = "<{$parameter[0]} xsi:type=\"{$parameter[1]}\">{$parameter[2]}     </{$parameter[0]}>\n"; } $request = <<< End_Of_Quote <SOAP-ENV:Envelope   xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"   xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"   xmlns:xsd="http://www.w3.org/1999/XMLSchema"   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">   <SOAP-ENV:Header>     <RequesterCredentials xmlns="urn:ebay:api:PayPalAPI"       SOAP-ENV:mustUnderstand="1">       <Credentials xmlns="urn:ebay:apis:eBLBaseComponents">         <Username>$username</Username>         <Password>$password</Password>         <Subject/>       </Credentials>     </RequesterCredentials>   </SOAP-ENV:Header>   <SOAP-ENV:Body>     <{$specificAPIName}Req xmlns="urn:ebay:api:PayPalAPI">       <{$specificAPIName}Request xsi:type="ns:{$specificAPIName}RequestType">         <Version xmlns="urn:ebay:apis:eBLBaseComponents"           xsi:type="xsd:string">1.0</Version>         $parameterList       </{$specificAPIName}Request>     </{$specificAPIName}Req>   </SOAP-ENV:Body> 

Every PayPal API call uses the same structure for its body: the name of the specific call being made, followed with a suffix depending on where it's being used. This allows for easy use throughout the body.

 </SOAP-ENV:Envelope> End_Of_Quote;   $ch = curl_init();   curl_setopt($ch, CURLOPT_URL, "https://api.sandbox.paypal.com/2.0/");   curl_setopt($ch, CURLOPT_SSLCERT, "../certs/cert_key_pem-1.txt");   curl_setopt($ch, CURLOPT_POST, TRUE);   curl_setopt($ch, CURLOPT_POSTFIELDS, $request);   curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);   $response = curl_exec($ch);   echo $response;   if (curl_error($ch))  {    file_put_contents("/tmp/curl_error_log.txt", curl_errno($ch) . ": ". curl_error($ch), "a+");    curl_close($ch);    return null;  }else  {    curl_close($ch);     $xml = simplexml_load_string($response);     return $xml;  } } 

This function, because it follows PayPal's general structure for all its API requests, should be able to complete any task you require of the API. The responses it gives will be identical to previous examples. To complete the details request shown earlier with this function, you would do this:

 $parameters[] = array("TransactionID", "ebl:TransactionId", "8N604562NC480291D"); $xml = makeCall("GetTransactionDetails", $parameters); 

To complete the refund, you would just need to add an additional parameter:

 $parameters[] = array("RefundType", "ebl:token", "Full"); 

That's it.




Professional Web APIs with PHP. eBay, Google, PayPal, Amazon, FedEx, Plus Web Feeds
Professional Web APIs with PHP. eBay, Google, PayPal, Amazon, FedEx, Plus Web Feeds
ISBN: 764589547
EAN: N/A
Year: 2006
Pages: 130

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net