While I've integrated several payment processors and shopping carts in the past, this Google Checkout API integration is not going well for me. I get a 400 response from Google, even when I use the diagnostic link. I'm sure something's wrong in my URL, but I can't seem to figure out what. I'm using a sandbox Merchant ID and Key.
Can someone help me see what I'm doing to get this 400 response, please?
I am using Java and posting from a server thus I'm calling the server to server API link:
https://sandbox.google.com/checkout/api/checkout/v2/merchantCheckout/Merchant/%SANDBOXID%
<?xml version="1.0" encoding="UTF-8"?>
<checkout-shopping-cart xmlns="http://checkout.google.com/schema/2">
<shopping-cart>
<merchant-private-data>
<merchant-note>8Ra8fw4tBaOdP4v3lseykKO6crR0dFqhzWV0EmqKuVuQaN1w0mcScAAR71pbexXlVnrwpP8wNzehuc7wz3KO9JM6xfedW8106olarCZcZBs=</merchant-note>
</merchant-private-data>
<items>
<item-name>MyName : MySubname</item-name>
<item-description>Weigh in on this year's...</item-description>
<unit-price currency="USD">100</unit-price>
<quantity>1</quantity>
</items>
</shopping-cart>
</checkout-shopping-cart>
I am using Java to post this data. In the code below, the url above is sandboxLink in the code and checkReq is the XML post...
public static String postCheckoutReqData(String userID, String gameName, boolean test) {
String checkRequest = GoogleCheckoutXML.getCheckoutRequestXML(userID, gameName);
if(checkRequest.indexOf("error,") != -1) return checkRequest;
URL url = null;
try {
String baseCodeString;
if(test) {
url = new URL(GoogleCheckoutXML.sandboxLink + GoogleCheckoutXML.sandboxMerchID);
baseCodeString = GoogleCheckoutXML.sandboxMerchID + ":" + GoogleCheckoutXML.sandboxMerchKey;
}
else {
url = new URL(GoogleCheckoutXML.productionLink + GoogleCheckoutXML.merchantID);
baseCodeString = GoogleCheckoutXML.merchantID + ":" + GoogleCheckoutXML.merchantKey;
}
//url = new URL(GoogleCheckoutXML.diagnose);
byte[] bytes = (baseCodeString.getBytes());
baseCodeString = new Base64().encodeAsString(bytes);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
conn.setRequestProperty("Authorization", "Basic " + baseCodeString);
conn.setRequestProperty("Content-Type", "application/xml; charset=UTF-8");
conn.setRequestProperty("Accept", "application/xml; charset=UTF-8");
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(checkRequest);
wr.flush();
// Get the response
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
line = line + rd.readLine();
}
wr.close();
rd.close();
return line;
}
catch (Exception e) {
e.printStackTrace();
return "error,Purchase Error posting communcation failed";
}
The actual stack trace in Tomcat is:
java.io.IOException: Server returned HTTP response code: 400 for URL: https://sandbox.google.com/checkout/api/checkout/v2/merchantCheckout/Merchant/[withheld]
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1612)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at com.[withheld]..GoogleCheckoutXML.postCheckoutReqData(GoogleCheckoutXML.java:194)
at com.[withheld]...l.getCheckoutLink(DubQueryImpl.java:270)
at com.[withheld]....GenerateCheckoutLinkServlet.doGet(GenerateCheckoutLinkServlet.java:56)
at com.[withheld]...doPost(GenerateCheckoutLinkServlet.java:73)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
I think I've solved a similar issue - it may, or may not, be yours ...
Check the return code:
int code = conn.getResponseCode(); // Integer (would be 400 in the case you give above) \String msg = conn.getResponseMessage(); // String (would be "Bad Request" in the case you give above
Check for further details
InputStream in = new BufferedInputStream(conn.getErrorStream());
Read in to see what further information is being provided - I have found it to be quite helpful!
In my case, my carefully prepared xml was losing the quotation marks somewhere along the way, trashing the <xml version="1.0" ... >
right at the start and wreaking havoc from then onwards ...