Send a receipt after accepting payment on a Typeform

Nicolas Grenié
Typeform's Engineering Blog
4 min readFeb 5, 2019

It’s been a few weeks since I last dedicated an afternoon to hack something. So you couldn’t imagine how happy I was when I decided to devote my Thursday afternoon to hacking.

Me in the office 🐼

I had a few ideas in my backlog, but before going headfirst into my coding rabbit hole, I decided to lurk in one of our Slack channels. There, I naively asked for feedback on an initial idea to hack together Typeform and Stripe. Almost immediately, our awesome Support Manager Chris spoke up and advocated for something our customers have been asking for a lot: a way to send a receipt after receiving money through a Typeform.

If you were not already aware, we have a special question on Typeform that lets you accept credit card payments using Stripe. When using this question type, you can turn your simple typeform into a full e-commerce website, without a line of code! Read more about in our Help Center.

So my idea was set: at the end of this hacking session, I would have a working solution to send receipts! (spoiler: I’ve found a way 😉)

Try it live 📺

If you want to have a sense of what we will be building, feel free to check this typeform.
There, you’ll be able to buy tickets for a fake raffle lottery.
After leaving your email and entering your credit card details, you will be charged $1, and you should receive a receipt by email.
Hopefully, it will look like this 👇

Example of a receipt, yes it’s a 🧀 business, yes it exists, check it out on SFCheeseParty.com

Webhooks to the rescue ⛑️

As with most of our integrations, building a real-time experience requires webhooks.

When you are processing a payment through Typeform using Stripe, the webhook payload for a payment question’s answer looks like this:

{
"type": "payment",
"payment": {
"amount": "1",
"last4": "1234",
"name": "John Doe",
"success": true
},
"field": {
"id": "NO15xU3S8cbX",
"type": "payment",
"ref": "payment_block"
}
}

In my form, I would also need an email field so I can send the receipt to this email address and associate the payment object to it.

My first step was to extract those values just after receiving the webhook event from Typeform.

let email = req.body.form_response.answers.find((a)=> a.type==='email').email
let payment_details = req.body.form_response.answers.find((a)=> a.type==='payment').payment

Now I just had to link this payment to something on Stripe’s backend.

Which Stripe APIs should I use? 🤔

According to Stripe’s documentation, they have a built-in way to send receipts. Just add the receipt_email property when you are creating a charge, as described here.

Unfortunately, this step is happening on Typeform’s backend, and I don’t get to mess around there, we have proper engineers for that 😉

Later on, I thought I could use the Invoice mechanism. But I quickly realized it would not fit for this use case. While Invoice gives a lot of space for creativity and complexity, it emails an invoice to a customer and requests them to pay it. In our case, the transaction already happened and was already paid.

It all starts with a charge 💸

Finally, I looked at investigating charges on my stripe account. And I tried to see if I could isolate the one that just happened on my typeform.

To do that you will need your Stripe API keys:

const stripe = require("stripe")(process.env.STRIPE_LIVE_API_KEY);
let charges = await stripe.charges.list({ limit: 3 })
let corresponding_charge = charges.data.find((c) => c.metadata.typeform_form_id === form_response.form_id && c.metadata.typeform_response_id === form_response.token) // check metadata of charges

Using Stripe SDK, I look for the latest three charges and find which one matches the corresponding transaction inspecting charge metadata.

While I looked at the detail of the corresponding_charge object, I saw that there was a receipt_url property with a URL in it. And surprise! 🎉 If you open this URL, you have a beautifully branded receipt generated by Stripe. That was something I could use! 💪

There was also a receipt_email property, so why not try to update this value and see what happens?

corresponding_charge = await stripe.charges.update(corresponding_charge.id,{ receipt_email: email})

Thanks to a discussion on a Google Group, I’ve found that by updating this particular field, Stripe will send the generated receipt to this email.

Using the same technique, you can also add metadata to the charge on Stripe, like auser_id or order_id to your typeform as a hidden field.

My job was done here 🎉

How to implement on your typeform?🛠️

You too can now send a receipt after accepting a Stripe transaction on typeform.

You need:

  • a Stripe account
  • a Typeform PRO account (create one here, 14 days free trial)
  • an email field in your typeform ✉️
  • a payment field in your typeform 💰

1️⃣ Step 1: Remix this 🎏Glitch project

2️⃣ Step 2: in the .env file paste your Stripe live API key.

3️⃣ Step 3: Get the URL of your Glitch project by clicking on the Show Button on the top. Copy this URL. And paste it in the webhook panel of your form (Connect > Webhooks)
URL should be of the formhttps://{random_names}.glitch.me/webhook

4️⃣ Pay and celebrate 🎉: Open your form and make a $1 payment. You should automatically receive an email containing an auto-generated receipt.

For this hack, I am using Glitch as a way to host my webhook handler, but the code should be the same if you deploy it on your own server or any FaaS service (AWS Lambda, Zeit, …).

Hope you like it 😉
Feel free to drop other ideas in the comments and eventually our DevRel team will pick it up!

--

--

Nicolas Grenié
Typeform's Engineering Blog

@typeform Dev Advocate, ex-@3scale, @sfcheeseparty enthusiast — G33k 🤓, fun🤘, frogs🐸 and snails🐌!