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

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:

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)
.autoReturn(3_200, MILLISECONDS)
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\",

It works!

Receipt printing works as well!

Now let’s focus on Google Home.

If Tired Then Triple (shot)

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(
+ "\"to\":\"%s\"}",
URL url = new URL("https://fcm.googleapis.com/fcm/send");
HttpURLConnection conn =
(HttpURLConnection) url.openConnection();
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "key=" + apiKey);
OutputStreamWriter writer =
new OutputStreamWriter(conn.getOutputStream());

response.getWriter().println("Over Extracted?");

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

The Full Picture

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…

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.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

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