Skip to content

Instantly share code, notes, and snippets.

@gregberns
Last active September 10, 2020 23:31
Show Gist options
  • Save gregberns/6058b0e4cb4822941fbf026e8c82d290 to your computer and use it in GitHub Desktop.
Save gregberns/6058b0e4cb4822941fbf026e8c82d290 to your computer and use it in GitHub Desktop.

Stripe Payment Example

Example of how to use Stripe.js and Node.JS libraries.

  • index.html - Client side workflow (JS)
  • index.js - Server side workflow (Node.JS)

Note: Examples are a very rough POC, so please excuse the rough style.

<!doctype html>
<html>
<head>
<title>This is the title of the webpage!</title>
<script src="https://js.stripe.com/v3/"></script>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<p>This is an example paragraph. Anything in the <strong>body</strong> tag will appear on the page, just like this
<strong>p</strong> tag and its contents.</p>
<div>
<button onclick="submitPaymentIntent()">
Submit Payment Intent
</button>
</div>
<form id="payment-form" onsubmit="submitPayment(event)" class="payment-form">
<div id="card-element">
<!-- Elements will create input elements here -->
</div>
<!-- We'll put the error messages in this element -->
<div id="card-errors" role="alert"></div>
<button id="submit">Pay</button>
</form>
<script>
var stripe = Stripe('pk_test_51HJpxrGuRfJc1w8oW76xWsJTkrH3m4ZTzBHdFcnl9lV7s6s4JISnkm8mIozF8DROH5n0bTyosxSbSOYQNCVhkRsf008rpptWBx');
var elements = stripe.elements();
var style = {
base: {
color: "#32325d",
}
};
// a global
var card = elements.create("card", { style: style });
card.mount("#card-element");
var clientSecret = null;
function submitPaymentIntent() {
console.log("submitPaymentIntent() clicked")
const customerInfo = {
first_name: "first",
last_name: "last",
email: "",
address: {
// required
line1: "123 Main St",
line2: "Apt 2",
city: "Nowhere",
state: "AK",
postal_code: "90299",
// Two-letter country code (ISO 3166-1 alpha-2).
country: "us",
},
phone: "123-234-2345"
};
const products = [
1, 2, 3
];
const body = JSON.stringify({
customerInfo,
products,
})
console.log(`Start fetch POST /payments/provider/stripe/create-payment-intent | Body: ${body}`)
fetch('/payments/provider/stripe/create-payment-intent', {
method: 'POST',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json',
},
body,
}).then(function (response) {
console.log('End POST /payments/provider/stripe/create-payment-intent')
return response.json();
}).then(function (responseJson) {
clientSecret = responseJson.client_secret;
// Call stripe.confirmCardPayment() with the client secret.
console.log(`clientSecret returned: ${clientSecret}`)
});
}
function submitPayment(e) {
e.preventDefault()
console.log("Start submitPayment()")
// CF: TO FIGURE OUT
// Do the customer/payment_intent here???? ---->> ClientSecret
// idea: execute this to a CF API - so theres no page refresh
// CF side: CF Lib, Java lib, Azure API
stripe.confirmCardPayment(clientSecret, {
// Docs: "Use off_session if your customer may or may not be present in your checkout flow."
setup_future_usage: "off_session",
payment_method: {
card: card,
}
}).then(function (result) {
console.log(`confirmCardPayment Completed`)
if (result.error) {
// Show error to your customer (e.g., insufficient funds)
console.log(`confirmCardPayment ErrorMessage: ${result.error.message}, Result: ${JSON.stringify(result)}`);
} else {
console.log(`confirmCardPayment Success`)
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
console.log(`confirmCardPayment Status: Succeeded`)
// Show a success message to your customer
// There's a risk of the customer closing the window before callback
// execution. Set up a webhook or plugin to listen for the
// payment_intent.succeeded event that handles any business critical
// post-payment actions.
storePaymentIntent(result.paymentIntent)
}
}
}).catch(function (e) {
console.log(`confirmCardPayment Catch ${e}`);
});
}
function storePaymentIntent(paymentIntent) {
console.log(`Start fetch POST /payments/provider/stripe/payment-intent-complete. Body: ${JSON.stringify(paymentIntent)}`)
fetch('/payments/provider/stripe/payment-intent-complete', {
method: 'POST',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(paymentIntent)
}).then(function (res) {
console.log(`End POST /payments/provider/stripe/payment-intent-complete - Status: ${res.status}`)
// MUST REDIRECT to NEW PAGE + PREVENT USER FROM CLICKING BUTTON AGAIN!
}).catch(function (e) {
console.log(`End POST /payments/provider/stripe/payment-intent-complete - Error: ${e}`)
});
}
</script>
<style>
.payment-form {
width: 400px;
border-style: solid;
}
</style>
</body>
</html>
let express = require('express');
let app = express();
app.use(express.json())
app.use(express.static('public'))
function isNullOrEmpty(value) {
return value == undefined || value == null || value == ""
}
app.get('/health', function (req, res) {
// if (isNullOrEmpty(req.query) || isNullOrEmpty(req.query.echo)) {
// console.error('No "echo" query parameter supplied')
// res.status(400).send({ error: 'No "echo" query parameter supplied' })
// return;
// }
console.log('health')
res.json({ success: true });
})
app.post('/api', function (req, res) {
console.log(`Received message. Body: ${JSON.stringify(req.body)}. Headers: ${JSON.stringify(req.headers)}`)
res.status(200).send(new Buffer(`"Hello World"`));
})
// TODO: # Install Stripe via npm
// $ npm install --save stripe
// Set your secret key. Remember to switch to your live secret key in production!
// See your keys here: https://dashboard.stripe.com/account/apikeys
const stripe = require('stripe')('sk_test_51HJpxrGuRfJc1w8odYvPTdFMnNT0ieggBP02I0vSp12cGodXZoDRssYLw9Iok8fc6HLGQC0QkPnkNx2BrZkHITsY00ojVJnyK2');
// # Verify your integration in this guide by including the metadata parameter
// curl https://api.stripe.com/v1/payment_intents \
// -u sk_test_51HJpxrGuRfJc1w8odYvPTdFMnNT0ieggBP02I0vSp12cGodXZoDRssYLw9Iok8fc6HLGQC0QkPnkNx2BrZkHITsY00ojVJnyK2: \
// -d amount=1099 \
// -d currency=usd \
// -d "metadata[integration_check]"=accept_a_payment
app.post('/payments/provider/stripe/create-payment-intent', async (req, res) => {
console.log('Start POST /payments/provider/stripe/create-payment-intent')
console.log(req.body)
const { customerInfo, products } = req.body;
if (customerInfo == undefined) throw new Error("customerInfo undefined")
if (products == undefined) throw new Error("products undefined")
console.log(`Products: ${JSON.stringify(products)}`);
console.log(`Customer Info: ${JSON.stringify(customerInfo)}`);
customerInfo.name = `${customerInfo.first_name} ${customerInfo.last_name}`;
delete customerInfo.first_name
delete customerInfo.last_name
///
/// CREATE CUSTOMER
///
const customer = await stripe.customers.create(customerInfo)
.catch(e => {
console.log(`Error in stripe.paymentIntents.create(): ${e}`);
throw new Error(e)
});
console.log(`Stripe Customer Created: ${JSON.stringify(customer)}`);
const amount = calculateOrderAmount(products);
console.log('Start stripe.paymentIntents.create()')
///
/// CREATE PAYMENT INTENT
///
const intent = await stripe.paymentIntents.create({
amount,
currency: 'usd',
customer: customer.id,
// Verify your integration in this guide by including this parameter
metadata: {
integration_check: 'accept_a_payment',
// maybe include a customer id?
},
}).catch(e => {
console.log(`Error in stripe.paymentIntents.create(): ${e}`);
throw new Error(e)
});
console.log(`End stripe.paymentIntents.create(): ${JSON.stringify(intent)}`)
console.log('End POST /payments/provider/stripe/create-payment-intent')
res.json({
client_secret: intent.client_secret
});
// res.send({
// publishableKey: process.env.STRIPE_PUBLISHABLE_KEY,
// clientSecret: paymentIntent.client_secret
// });
});
calculateOrderAmount = (items) => 4200;
// Result Wrapper + Payment Intent
// {
// "id": "pi_1HPbH1GuRfJc1w8oAEfAq1vU",
// "object": "payment_intent",
// "amount": 4200,
// "canceled_at": null,
// "cancellation_reason": null,
// "capture_method": "automatic",
// "client_secret": "pi_1HPbH1GuRfJc1w8oAEfAq1vU_secret_jvhEkgUb1urOSiMspm2V7lYKV",
// "confirmation_method": "automatic",
// "created": 1599688575,
// "currency": "usd",
// "description": null,
// "last_payment_error": null,
// "livemode": false,
// "next_action": null,
// "payment_method": "pm_1HPbHJGuRfJc1w8o5P9cp2at",
// "payment_method_types": [
// "card"
// ],
// "receipt_email": null,
// "setup_future_usage": null,
// "shipping": null,
// "source": null,
// "status": "succeeded"
// }
app.post('/payments/provider/stripe/payment-intent-complete', async (req, res) => {
console.log(`POST /payments/provider/stripe/payment-intent-complete : Body: ${JSON.stringify(req.body)}`)
res.status(201).end();
})
const endpointSecret = 'whsec_...';
app.post('/payments/provider/stripe/webhook', function (request, response) {
const sig = request.headers['stripe-signature'];
const body = request.body;
let event = null;
try {
event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
} catch (err) {
// invalid signature
response.status(400).end();
return;
}
let intent = null;
switch (event['type']) {
case 'payment_intent.succeeded':
intent = event.data.object;
console.log("Succeeded:", intent.id);
break;
case 'payment_intent.payment_failed':
intent = event.data.object;
const message = intent.last_payment_error && intent.last_payment_error.message;
console.log('Failed:', intent.id, message);
break;
}
response.sendStatus(200);
});
var port = (process.env.PORT || 8081);
app.listen(port, function () {
console.log('Listening on port: ' + port);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment