Learn how to put a donation form on a website - using Netlify & Stripe - fully SCA compliant and no servers to manage!
We will:
- Host a static site on Netlify
- Use Stripe Checkout to handle the donation
- Wire it together with a serverless Netlify Function
tl;dr jump straight to the code here:
monty5811 / donate-form
example severless donate form with stripe & netlify
donate-form
This repo is an example of how to build a donation form with Stripe & Netlify.
There are two main components:
- A super simple form with some JS to handle the redirect flow
- A netlify function to talk to the Stripe API
Step 1: Setup
First of all we need a form where the user can choose how much to donate:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Serverless Donate Form</title>
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<style>
html {
font-family: 'Lucida Grande', Verdana, sans-serif;
}
</style>
</head>
<body class="h-screen flex flex-col justify-center">
<form class="antialiased max-w-xs mx-auto" id="payment-form">
<input class="block w-64 py-2 px-3 mx-auto mb-4 border-gray-300 border rounded-md" type="number" min="0" placeholder="$50" id="giving-amount" />
<button class="bg-green-500 hover:bg-green-600 text-white py-2 px-4 rounded-full mx-auto block" id="giving-button">
Donate
</button>
</form>
</body>
</html>
Which looks something like this (we've used Tailwind for styling):
Step 2: Adding Stripe to the form
Now we need some javascript to handle the interaction with Stripe. We do a few different things to hook our form up to Stripe:
- Listen for the user submitting the form
- Update the form to a "waiting" state
- Get a Stripe Checkout Session ID from our lambda function
- Redirect to Stripe's hosted checkout with the Session ID
- Handle any errors
Required changes:
<!-- rest of content as above -->
<!-- add jquery & stripe -->
<script src="https://code.jquery.com/jquery-3.4.1.min.js" crossorigin="anonymous"></script>
<script src="https://js.stripe.com/v3/"></script>
<script type="text/javascript">
var errorText = "Failed. You have not been charged.";
// look out for submit events on the form
document.addEventListener("DOMContentLoaded", function(event) {
var submitButton = document.getElementById("giving-button");
var stripe = Stripe("<YOUR_STRIPE_PUBLISHABLE_KEY_HERE>");
var form = document.getElementById("payment-form");
form.addEventListener("submit", function(event) {
event.preventDefault();
const buttonText = submitButton.innerText;
submitButton.innerText = "Working...";
var data = {
amount: document.getElementById("giving-amount").valueAsNumber * 100,
};
// create a stripe session by talking to our netlify function
$.ajax({
type: "POST",
url: "/.netlify/functions/get_checkout_session/",
data: JSON.stringify(data),
success: function(data) {
// we got a response from our netlify function:
switch (data.status) {
case "session-created":
// it worked - send the user to checkout:
stripe
.redirectToCheckout({
sessionId: data.sessionId
})
.then(function(result) {
submitButton.innerText = result.error.message;
});
break;
default:
submitButton.innerText = errorText;
}
},
dataType: "json"
});
});
});
</script>
</body>
</html>
Step 3: Add our lambda function
Now we have a form that will take the donation amount & redirect to Stripe's hosted checkout. However, in order to use a custom "price" with Stripe Checkout we need a server-side component.1
Setting up a whole server seems like overkill for this - a serverless function is ideal.
The serverless function simply takes the amount and gets a Session ID from Stripe. This Session ID is then sent back to the browser where the user is redirected to complete their donation.
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY); // get from ENV
const headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type"
};
exports.handler = function(event, context, callback) {
// some error checking:
if (event.httpMethod !== "POST" || !event.body) {
callback(null, {
statusCode: 400,
headers,
body: JSON.stringify({ status: "bad-payload" })
});
}
// Parse the body contents into an object.
const data = JSON.parse(event.body);
// Make sure we have all required data. Otherwise, escape.
if (!data.amount) {
console.error("Required information is missing.");
callback(null, {
statusCode: 400,
headers,
body: JSON.stringify({ status: "missing-information" })
});
return;
}
// actually create the session with Stripe
// we need to provide a couple of redirect urls:
stripe.checkout.sessions.create(
{
success_url: "https://donate-form-example.netlify.com/success",
cancel_url: "https://donate-form-example.netlify.com/cancel",
payment_method_types: ["card"],
billing_address_collection: "required",
payment_method_types: ["card"],
submit_type: "donate",
line_items: [
{
name: "Donation!",
amount: data.amount,
currency: "usd",
quantity: 1
}
]
},
function(err, session) {
// asynchronously called
if (err !== null) {
console.log(err);
callback(null, {
statusCode: 200,
headers,
body: JSON.stringify({ status: "session-create-failed" })
});
}
// woohoo! it worked, send the session id back to the browser:
callback(null, {
statusCode: 200,
headers,
body: JSON.stringify({
status: "session-created",
sessionId: session.id
})
});
}
);
};
You can see how this is hooked up to Netlify in the full repo:
monty5811 / donate-form
example severless donate form with stripe & netlify
donate-form
This repo is an example of how to build a donation form with Stripe & Netlify.
There are two main components:
- A super simple form with some JS to handle the redirect flow
- A netlify function to talk to the Stripe API
Conclusions
That's it! We have built a donation form where a user can choose how much they would like to donate and we have done it without ever having to worry about running our own server.
You can just as easily do this for a non-static site - you just need to replace the serverless function with a route on your site that will create a Stripe Session & return the id to the frontend.
-
If you have fixed prices, or fixed donation amounts, then you don't need any server side components. You can do everything client side. See the Stripe docs for more infoΒ β©
Top comments (0)