Ok Google, Charge $2 for Coffee

Py ⚔
Py ⚔
Mar 10, 2017 · 5 min read

Heads up, we’ve moved! If you’d like to continue keeping up with the latest technical content from Square please visit us at our new home https://developer.squareup.com/blog

When I received my Google Home, I immediately felt the urge to build something with it. After a good night’s sleep, I had an idea: Baristas and business owners usually have their hands full behind the counter. What if they could complete transactions without tapping buttons at their point of sale? What if a merchant could accept Apple Pay transactions using only their voice?

In the video, we’re using Google Home to activate the Square Contactless Reader and take a real Apple Pay transaction backed by a Square Cash virtual card.

This was built in a few hours using only public APIs. Let’s look at how it works!

Turning voice into coffee

Image for post
Image for post

While baristas make it look really simple, making espresso actually depends on many moving parts. Similarly, the above diagram is really a large oversimplification. Many more components were involved in enabling this seemingly simple transaction.

Roasting the Java beans

That means we can build a custom merchant app that calls the Point-of-Sale API. Once in the foreground, the Point-of-Sale app activates the NFC chip in the reader over bluetooth:

Image for post
Image for post

Let’s create a new Android app, Home Charge, that triggers the Point-of-Sale API! According to the documentation, we just need to register our new app, then add a dependency and a few lines of code:

public class ChargeActivity extends Activity {
// ...
public void startTransaction(int dollarAmount, String note) {
ChargeRequest request =
new ChargeRequest.Builder(dollarAmount * 1_00, USD)
.note(note)
.autoReturn(3_200, MILLISECONDS)
.restrictTendersTo(CARD)
.build();
Intent intent = posClient.createChargeIntent(request);
startActivityForResult(intent, CHARGE_REQUEST_CODE);
}
}

Pushing the tamper down

Let’s use Firebase Cloud Messaging to push server messages to our app. The setup is straightforward, and we just need to add a few lines of custom code:

public class ChargeService extends FirebaseMessagingService {

final Handler handler = new Handler(Looper.getMainLooper());

@Override public void onMessageReceived(RemoteMessage msg) {
Map<String, String> data = remoteMessage.getData();
final int dollarAmount = Integer.parseInt(data.get("amount"));
final String note = data.get("note");

handler.post(new Runnable() {
@Override public void run() {
startTransaction(dollarAmount, note);
}
});
}

private void startTransaction(int dollarAmount, String note) {
App app = (App) getApplicationContext();
ChargeActivity chargeActivity = app.getResumedChargeActivity();
if (chargeActivity != null) {
chargeActivity.startTransaction(dollarAmount, note);
}
}
}

We can retrieve the registration token with FirebaseInstanceId.getInstance().getToken() and manually test the app works with curl:

curl \
--header "Authorization: key=API_KEY" \
--header Content-Type:"application/json" \
https://fcm.googleapis.com/fcm/send \
-d \
"
{
\"data\": {
\"amount\": \"2\",
\"note\":\"coffee\"
},
\"to\":\"REGISTRATION_TOKEN\"
}"
Image for post
Image for post

It works!

Image for post
Image for post
Receipt printing works as well!

Now let’s focus on Google Home.

If Tired Then Triple (shot)

Image for post
Image for post

We also need to define an Action in response to that Trigger. IFTTT has a Maker channel that provides a Web Request Action. Unfortunately, we cannot use it to directly call the Firebase Cloud Messaging servers, because it does not support authorization headers.

Channeling the coffee stream

public class MessageServlet extends HttpServlet {  @Override public void doGet(
HttpServletRequest request,
HttpServletResponse response) throws IOException {
Map<String, String> queryParams = parseQueryParams(request);
String amount = queryParams.get("amount");
String note = queryParams.get("note");
String apiKey = queryParams.get("api-key");
String token = queryParams.get("registration-token");
String json = String.format(
"{\"data\":{\"amount\":\"%s\",\"note\":\"%s\"},"
+ "\"to\":\"%s\"}",
amount,
note,
token);
URL url = new URL("https://fcm.googleapis.com/fcm/send");
HttpURLConnection conn =
(HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "key=" + apiKey);
OutputStreamWriter writer =
new OutputStreamWriter(conn.getOutputStream());
writer.write(json);
writer.close();

response.setStatus(conn.getResponseCode());
response.setContentType("text/plain");
response.getWriter().println("Over Extracted?");
}
}

Then we just need to define the corresponding IFTTT Web Request Action:

Image for post
Image for post

The Full Picture

Image for post
Image for post

I hope you enjoyed this blog post! The sources for this project are available on GitHub. What cool things are you going to build on top of our public APIs?

Square Corner Blog

Buying and selling sound like simple things - and they…

Thanks to Tristan Sokol, Montana Scher, Ella Polo, Alex Rafter, Winnie Wu, and John Rodriguez

Py ⚔

Written by

Py ⚔

Android baker @Square. Twitter account: @Piwai

Square Corner Blog

Buying and selling sound like simple things - and they should be. Somewhere along the way, they got complicated. At Square, we're working hard to make commerce easy for everyone.

Py ⚔

Written by

Py ⚔

Android baker @Square. Twitter account: @Piwai

Square Corner Blog

Buying and selling sound like simple things - and they should be. Somewhere along the way, they got complicated. At Square, we're working hard to make commerce easy for everyone.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store