Saturday, August 7, 2010

PayPal Mass Payments using HttpClient 4

Here's another PayPal tip. The PayPal Mass Payments feature allows anyone with a Premier or Business account to send multiple payments instantly—saving time, money and the hassle of having to individually send funds to every payment recipient.

In this tip I will show you how to make a mass payment using the apache httpclient library (http://hc.apache.org/httpcomponents-client/index.html), version 4.

First we define some constants we'll need in the code:

private NumberFormat paypalNumberFormat = new DecimalFormat("0.00", new DecimalFormatSymbols(Locale.US));
private static final String PAYPAL_URL = "https://api-3t.sandbox.paypal.com/nvp"; //Remove the ".sandbox" if you want to use the live environment
private static final String PAYPAL_USER = "username";
private static final String PAYPAL_PASSWORD = "password";
private static final String PAYPAL_SIGNATURE = "signature";

Here's the code to make the actual call:

HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(PAYPAL_URL);
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("USER", PAYPAL_USER));
params.add(new BasicNameValuePair("PWD", PAYPAL_PASSWORD));
params.add(new BasicNameValuePair("SIGNATURE", PAYPAL_SIGNATURE));
params.add(new BasicNameValuePair("VERSION", "2.3"));
params.add(new BasicNameValuePair("METHOD", "MassPay"));
params.add(new BasicNameValuePair("RECEIVERTYPE", "EmailAddress"));
params.add(new BasicNameValuePair("L_EMAIL0", email));
params.add(new BasicNameValuePair("L_AMT0", paypalNumberFormat.format(amountToSend)));
params.add(new BasicNameValuePair("CURRENCYCODE", "USD"));
post.setEntity(new UrlEncodedFormEntity(params));
HttpResponse response = client.execute(post);

This sample will send 1 payment to the PayPal account in the email variable and with the amount in the amountToSend variable. The parameters are called L_EMAIL0 and L_AMT0. Since this is the mass payments API, you can send more than one payment. To do so, just add 2 new parameters for each payment you want to make: L_EMAILx for the PayPal account you want to send the money to and L_AMTx for the amount you want to transfer. x is a number from 0 to 255, making the maximum number of simultaneous payments you can make 256.

PayPal sends back a couple of parameters. You will probably want to check the "ACK" parameter, which tells you if your call succeeded. See https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_nvp_NVPAPIOverview for an overview of the parameters and their values returned by PayPal. Here is a way to parse the response:

private Map<String, String> parseResponse(HttpResponse response) throws IllegalStateException, IOException {
Map<String, String> map = new HashMap<String, String>();
String responseStr = getResponseContent(response);
List<NameValuePair> responseParams = new ArrayList<NameValuePair>();
URLEncodedUtils.parse(responseParams, new Scanner(responseStr), "UTF-8");
for (NameValuePair nvp : responseParams) {
map.put(nvp.getName(), nvp.getValue());
}
return map;
}

private String getResponseContent(HttpResponse response) throws IOException, IllegalStateException {
InputStream is = response.getEntity().getContent();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String result = "";
String line = null;
while ((line = br.readLine()) != null) {
result += line;
}
return result;
}

You can call it like this:

Map<String, String> responseParams = parseResponse(response);
String ack = responseParams.get("ACK");
if (ack != null && ack.indexOf("Success") >= 0) {
//Do something
} else {
//Do something else
}

3 comments:

  1. Mathiasde, trust you well.

    On the MassPay Subject, we had an issue with SSLHandshakeException when we tried to invoke the Live MassPayAPI on the PayPal site. I am using the PayPal SDK and I downloaded the Certificate from my account and used.. CertificateAPIProfile profile = new CertificateAPIProfile();
    HERE is the StackTrace:

    avax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at com.paypal.sdk.core.soap.SOAPAPICaller.callSOAP(SOAPAPICaller.java:462)
    at com.paypal.sdk.core.soap.SOAPAPICaller.call(SOAPAPICaller.java:382)
    at com.paypal.sdk.services.CallerServices.call(CallerServices.java:125)
    at com.paypal.ejb.TimerServiceImpl.processPayPalMassPayment(TimerServiceImpl.java:1055)
    at com.paypal.ejb.TimerServiceImpl.triggerPayPalApiForBatch(TimerServiceImpl.java:1037)
    at com.paypal.ejb.TimerServiceImpl.doTimerTask(TimerServiceImpl.java:149)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeTarget(MethodInvocation.java:122)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:111)
    at org.jboss.ejb3.EJBContainerInvocationWrapper.invokeNext(EJBContainerInvocationWrapper.java:69)
    at org.jboss.ejb3.interceptors.aop.InterceptorSequencer.invoke(InterceptorSequencer.java:73)
    at org.jboss.ejb3.interceptors.aop.InterceptorSequencer.aroundInvoke(InterceptorSequencer.java:59)
    at sun.reflect.GeneratedMethodAccessor922.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.jboss.aop.advice.PerJoinpointAdvice.invoke(PerJoinpointAdvice.java:174)
    at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
    at org.jboss.ejb3.interceptors.aop.InvocationContextInterceptor.fillMethod(InvocationContextInterceptor.java:72)
    Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at org.apache.axis.AxisFault.makeFault(AxisFault.java:104)
    at org.apache.axis.transport.http.HTTPSender.invoke(HTTPSender.java:154)
    at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)
    at org.apache.axis.SimpleChain.doVisiting(SimpleChain.java:118)
    at org.apache.axis.SimpleChain.invoke(SimpleChain.java:83)
    at org.apache.axis.client.AxisClient.invokeTransport(AxisClient.java:150)
    at org.apache.axis.client.AxisClient.invoke(AxisClient.java:289)
    at org.apache.axis.client.Call.invokeEngine(Call.java:2838)
    at org.apache.axis.client.Call.invoke(Call.java:2824)
    at org.apache.axis.client.Call.invoke(Call.java:2501)
    at org.apache.axis.client.Call.invoke(Call.java:2424)
    at org.apache.axis.client.Call.invoke(Call.java:1835)
    at com.paypal.soap.api.PayPalAPISoapBindingStub.massPay(Unknown Source)
    ... 61 more

    I am suspecting that we are using the wrong API server IP addresses. Are these correct?
    (https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer
    /howto_api_golivechecklist)

    ReplyDelete
  2. Hi,

    It looks like you are using the SOAP API. I've never used that API, so I'm afraid I can't help you with that. As you can see in my code, I use the NVP (Name Value Pair) API. The live server address for the NVP interface is "https://api-3t.paypal.com/nvp". This may be different for the SOAP API.

    Here's some more info on the SOAP API: http://www.paypalobjects.com/en_US/ebook/PP_APIReference/Appx-SDKjava.html#1207809

    If that doesn't help you I would try posting on the PayPal forums (https://www.x.com/docs/DOC-1613).

    ReplyDelete
  3. Thanks, I will check the links you provided...

    ReplyDelete