I'm following this example integration from Stripe Docs (slightly modified in order to be able to add click handlers to more than one button:
<script src="https://checkout.stripe.com/checkout.js"></script>
<button id="customButton">Purchase</button>
<script>
var handler = StripeCheckout.configure({
key: 'pk_test_jPVRpCB1MLjWu2P71eTvXBZD',
image: '/square-image.png',
token: function(token) {
// Use the token to create the charge with a server-side script.
// You can access the token ID with `token.id`
}
});
$('.pay-deposit').click( function(e) {
// Open Checkout with further options
handler.open({
name: 'Demo Site',
description: '2 widgets ($20.00)',
amount: 2000
});
e.preventDefault();
});
In my particular case I have a few buttons like:
<button class='pay-deposit' booking-id='3455'>Pay Deposit</button>
<button class='pay-deposit' booking-id='335'>Pay Deposit</button>
<button class='pay-deposit' booking-id='34'>Pay Deposit</button>
... and obviously I'd like to pass a booking-id of clicked button somehow to token callback. Couldn't find any example or explanation covering this seemingly simple case... any help much appreciated. thanks!
This is a little bit late, but maybe it will help someone else. This is modified from a Rails example:
# HTML file
<script src="https://checkout.stripe.com/checkout.js"></script>
<button class='pay-deposit' data-booking-id='3455'>Pay Deposit</button>
<button class='pay-deposit' data-booking-id='335'>Pay Deposit</button>
<button class='pay-deposit' data-booking-id='34'>Pay Deposit</button>
# JS file
$('.pay-deposit').on('click', function(event) {
event.preventDefault();
// Get booking information from database
var booking_id = $(this).data('booking-id');
$.getJSON("/bookings/"+booking_id, function(data) {
// Open Checkout with further options
handler = stripe_checkout(booking_id);
handler.open({
name: "My Bookings",
description: data["description"],
amount: data["amount"],
email: data["email"],
});
// Close Checkout on page navigation
$(window).on('popstate', function() {
handler.close();
});
});
});
function stripe_checkout(booking_id) {
var handler = StripeCheckout.configure({
key: 'pk_test_jPVRpCB1MLjWu2P71eTvXBZD',
token: function(token) {
// Send the charge through
$.post("/charges/create",
{ token: token.id, booking_id: booking_id }, function(data) {
if (data["status"] == "ok") {
window.location = "/some-url";
} else {
// Deal with error
alert(data["message"]);
}
});
}
});
return handler;
}
# Bookings controller
class BookingsController < ApplicationController
def show
#booking = Booking.find(params[:id])
attrs = #booking.attributes
attrs.merge!("email" => current_user.email)
respond_to do |format|
format.json { render json: attrs.to_json }
end
end
end
# Charges controller
class ChargesController < ApplicationController
def create
booking = Booking.find(params[:booking_id])
customer = Stripe::Customer.create(card: params[:token])
charge = Stripe::Charge.create(
customer: customer.id,
amount: booking.amount,
description: booking.description,
currency: 'usd'
)
if charge.paid
# Do some things for successful charge
respond_to do |format|
format.json { render json: {status: "ok"}.to_json }
end
else
respond_to do |format|
format.json { render json: {status: "fail", message: "Error with processing payment. Please contact support."}.to_json }
end
end
end
end
Move your token initializer from configure to open.
var handler = StripeCheckout.configure({
key: 'pk_test_jPVRpCB1MLjWu2P71eTvXBZD',
image: '/square-image.png'
});
$('.pay-deposit').click( function(e) {
var data = $(this).data('booking-id');
// Open Checkout with further options
handler.open({
name: 'Demo Site',
description: '2 widgets ($20.00)',
amount: 2000,
token: function(token) {
// here you go!
alert(data);
}
});
e.preventDefault();
});
And switch to:
<button class='pay-deposit' data-booking-id='3455'>Pay Deposit</button>
<button class='pay-deposit' data-booking-id='335'>Pay Deposit</button>
<button class='pay-deposit' data-booking-id='34'>Pay Deposit</button>
Related
i am using stripe on my ruby on rails 5 website for my payment gateway plans. I am using the api in the client-side just as it appears in this link. I need to add a coupon to my plan, I could create it in the stripe dashboard in the testmode like the plan but adding the id to the code doesn't redirect me to the stripe checkout page. this is my javascript code:
<script src="https://js.stripe.com/v3"></script>
<script type="text/javascript">
$(document).ready(function() {
var stripe = Stripe('<%= Rails.configuration.stripe[:publishable_key] %>');
$('.payment-action').on('click', function() {
const data = $(this).data();
const user_email = '<%= current_user ? current_user.email : ""%>'
const user = '<%= current_user.id%>'
stripe.redirectToCheckout({
lineItems: [{
// Define the product and price in the Dashboard first, and use the price
// ID in your client-side code. You may also pass a SKU id into the `price`
// field
price: data['plankey'],
quantity: 1
}],
customerEmail: user_email,
mode: 'subscription',
subscriptionData: {
coupon: 'WaS5wFHC'
},
successUrl: 'https://www.my_web.network/success_payment?session_id={CHECKOUT_SESSION_ID}&p_i='+data['plan']+'&us='+user,
cancelUrl: 'https://www.my_web.network/update_plan'
});
});
});
</script>
I've been trying to get it to appear on this page using subscription_data or subscriptionData but it still doesn't work, what could I be missing?
<script type="text/javascript">
$(document).ready(function() {
var stripe = Stripe('<%= Rails.configuration.stripe[:publishable_key] %>');
$('.payment-action').on('click', function() {
const data = $(this).data();
const user_email = '<%= current_user ? current_user.email : ""%>'
const user = '<%= current_user.id%>'
stripe.redirectToCheckout({
lineItems: [{
// Define the product and price in the Dashboard first, and use the price
// ID in your client-side code. You may also pass a SKU id into the `price`
// field
price: data['plankey'],
quantity: 1
}],
customerEmail: user_email,
mode: 'subscription',
subscription_data: {
coupon: 'WaS5wFHC'
},
successUrl: 'https://www.my_web.network/success_payment?session_id={CHECKOUT_SESSION_ID}&p_i='+data['plan']+'&us='+user,
cancelUrl: 'https://www.my_web.network/update_plan'
});
});
});
</script>
It's not possible to use coupons for subscriptions in client-side only Checkout. You'd have to create a Checkout Session on your server where you pass in your coupon ID: https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-subscription_data-coupon
I'm trying to integrate Stripe custom checkout https://stripe.com/docs/checkout#integration-custom with Flask and WTForms. My problem at the moment is the payment form doesn't seem to be posting so the credit card charge cannot be created.
It seems the form is recognised because the token is being posted to stripe's api with a 200 response:
XHRPOST
https://api.stripe.com/v1/tokens
[HTTP/2.0 200 OK 1444ms]
Form data
card[cvc] 123
card[exp_month] 10
card[exp_year] 20
card[name] dev#local.host
card[number] 4242424242424242
email dev#local.host
guid 4a6cfd25-8c4b-4d98-9dd2-9e9c1770e290
key pk_test_DVVO0zxtWjXSZx4yHsZGJxtv
muid c6b9d635-20de-4fc6-8995-5d5b2d165881
payment_user_agent Stripe+Checkout+v3+checkout-manhattan+ (stripe.js/9dc17ab)
referrer http://localhost:8000/subscription/index
sid 494d70dd-e854-497b-945b-de0e96a0d646
time_on_page 26657
validation_type card
However the token (and the form) is not being posted to my server to create the charge that stripe requires.
Here is the javascript code to load stripe custom checkout, which is in /index.html:
<script src="https://checkout.stripe.com/checkout.js"></script>
<form role="form" id = "payment_form" action="{{ url_for('billing.charge') }}" method="post">
{{ form.hidden_tag }}
<input type="hidden" id="stripeToken" name="stripeToken" />
<input type="hidden" id="stripeEmail" name="stripeEmail" />
<div class="form-group">
<div class="col-md-12 button-field" style = "text-align: center;">
<button type="confirm" id = 'confirm' onclick = "runStripe('https://checkout.stripe.com/checkout.js')" class="btn btn-default btn-responsive btn-lg">Confirm Order</button>
</div>
</div>
<script>
var handler = StripeCheckout.configure({
key: "{{ stripe_key }}",
locale: 'auto',
token: function(token) {
// token ID as a hidden field
var form = document.createElement("form");
form.setAttribute('method', "POST");
form.setAttribute('action', "{{ url_for('billing.charge') }}");
form.setAttribute('name', "payment-form");
var inputToken = document.createElement("input");
inputToken.setAttribute('type', "hidden");
inputToken.setAttribute('name', "stripeToken");
inputToken.setAttribute('value', token.id);
form.appendChild(inputToken);
// email as a hidden field
var inputEmail = document.createElement("input");
inputEmail.setAttribute('type', "hidden");
inputEmail.setAttribute('name', "stripeEmail");
inputEmail.setAttribute('value', token.email);
form.appendChild(inputEmail);
document.body.appendChild(form);
}
});
document.getElementById('confirm').addEventListener('click', function(e) {
// Open Checkout with further options:
handler.open({
name: 'Stripe.com',
description: '2 widgets',
amount: '{{ amount }}'
});
e.preventDefault();
});
// Close Checkout on page navigation:
window.addEventListener('popstate', function() {
handler.close();
});
</script>
<script>
document.getElementsByClassName("stripe-button-el")[0].style.display = 'none';
</script>
I have attempted a post method within the html tag with no success. I have also tried adding a form variable within the javascript token to post to my charge route, adapted from this question: Stripe Checkout Link onClick does not process payment
Here is my index and charge routes for reference:
#billing.route('/index', methods=['GET', 'POST'])
def index():
stripe_key = current_app.config.get('STRIPE_PUBLISHABLE_KEY')
amount = 1010
form = CreditCardForm(stripe_key=stripe_key)
return render_template('billing/index.html', stripe_key=stripe_key, form=form)
#billing.route('/charge', methods=['GET', 'POST'])
def charge():
if request.method == 'POST':
customer = stripe.Customer.create(
email = current_user,
source = request.form['stripeToken']
)
charge = stripe.Charge.create(
customer = customer.id,
amount = 2000,
currency = 'usd',
description = 'payment'
)
return render_template('charge.html', customer=customer, charge=charge)
I decided to change the token to jquery, which now seems to work perfectly and is far simpler:
<script>
var handler = StripeCheckout.configure({
key: "{{ stripe_key }}",
locale: 'auto',
token: function(token) {
$(document).ready(function(){
$("#stripeToken").val(token.id);
$("#stripeEmail").val(token.email);
$("#payment_form").submit();
})
</script>
In order for the jquery to be recognised, I also added the script for the jquery package at the top of the html file:
script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
Finally, for anone else who needs help in flask, here is my adjusted route:
#billing.route('/index', methods=['GET', 'POST'])
#handle_stripe_exceptions
#login_required
def index():
stripe_key = current_app.config.get('STRIPE_PUBLISHABLE_KEY')
amount = 1010
form = CreditCardForm(stripe_key=stripe_key, name=current_user.name, amount=amount )
if request.method == 'POST':
customer = stripe.Customer.create(
email='customer#example.com',
source=request.form['stripeToken']
)
charge = stripe.Charge.create(
customer=customer.id,
amount=amount,
currency='usd',
description='Flask Charge'
)
return render_template('billing/index.html', stripe_key=stripe_key, form=form)
I'm currently creating a job board where when a customer posts a job board they pay for it in one form and it will then post the job and charge there card all at once.
First, I used the standard Stripe Checkout button along with my listings form and it submitted both my form and took payment.
Then I tried customizing the Stripe Checkout button using the custom docs found here but I can't seem to understand what I'm missing.
Now when I click on the button it pops up like normal but when I submit the button my Rails form doesn't create nor does it charge Stripe.
listings_controller.rb
def create
p #listing = Listing.new(listing_params)
#categories = Category.all.map{|c| [ c.title, c.id ] }
charge_error = nil
p #listing.valid?
p #listing.errors
if #listing.valid?
begin
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:card => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #amount,
:description => 'New Job Posting',
:currency => 'usd'
)
rescue Stripe::CardError => e
p 'rescue'
p e
charge_error = e.message
end
if charge_error
p 'change error not nil'
p charge_error
flash[:error] = charge_error
render :new
else
p 'trying to save listing'
p #listing.save
redirect_to #listing
end
else
p 'listing not valid'
flash[:error] = 'one or more errors in your orders'
render :new
end
end
listings/_form.html.erb
//Top of the page //
<script src="https://checkout.stripe.com/checkout.js"></script>
<button class='btn btn-block btn-primary' id='customButton'>
Pay and Post Your Job Posting!
</button>
<% end %>
<script>
var handler = StripeCheckout.configure({
key: "pk_test_iSItYFJUx04fB9Ax6yGQjRDP",
image: "https://stripe.com/img/documentation/checkout/marketplace.png",
name: "Example Name",
description: "Pro Subscription ($29 per month)",
panelLabel: "Subscribe",
allowRememberMe: false,
locale: 'auto',
token: function(token) {
token.id
}
});
document.getElementById('customButton').addEventListener('click', function(e) {
handler.open({
name: 'Example Name #2',
description: 'Subscripe ($99/monthly)',
amount: 2000
});
e.preventDefault();
});
// Close Checkout on page navigation:
window.addEventListener('popstate', function() {
handler.close();
});
</script>
If you need any other info please ask. Thank you!
REFERENCE:
https://stripe.com/docs/sources/bitcoin
QUESTION:
I am trying to integrate Bitcoin payments to my code using Stripe.
From my understanding of the docs, I should create a Source object by creating a new form and on submit feed the data (in this case email and amount) to :
stripe.createSource({
type: 'bitcoin',
amount: 1000,
currency: 'usd',
owner: {
email: 'jenny.rosen#example.com',
},
}).then(function(result) {
// handle result.error or result.source
});
Then pass the result to the server to charge the Source object. Only issue: I don't see how to pass the result to the server. Should I create a new handler ?
var handler = StripeCheckout.configure({
key: 'key',
locale: 'auto',
name: 'website',
description: 'Secure Payment',
token: function(token) {
$('#stripeToken').val(token.id);
$("#stripeEmail").val(token.email);
$('form').submit();
}
});
I am lost.
Here is the code I currently have that works perfectly for USD payments.
MY CODE:
clientside (payment.ejs)
<% include partials/header %>
<div class="background">
<div class="message">
<div class="paymentBlock">
<h1 class="title">TITLE</h1>
<form class="paymentForm" action="/payment/charge" method="POST">
<input id="inputAmount" class="amountInput" name="amount" type="number/>
<input type="hidden" id="stripeToken" name="stripeToken" />
<input type="hidden" id="stripeEmail" name="stripeEmail"/>
<button type="submit" class="btn btn-success" id="paymentButton" >Submit Payment</button>
</form>
</div>
</div>
</div>
<script src="https://checkout.stripe.com/checkout.js"></script>
<script>
var handler = StripeCheckout.configure({
key: 'key',
locale: 'auto',
name: 'website',
description: 'Secure Payment',
token: function(token) {
$('#stripeToken').val(token.id);
$("#stripeEmail").val(token.email);
$('form').submit();
}
});
$('#paymentButton').on('click', function(e) {
e.preventDefault();
$('#error_explanation').html('');
var amount = $('#inputAmount').val();
amount = amount.replace(/\$/g, '').replace(/\,/g, '');
amount = parseFloat(amount);
if (isNaN(amount)) {
$('#error_explanation').html('<p>Please enter a valid amount in USD ($).</p>');
}
else if (amount < 1.00) {
$('#error_explanation').html('<p>Payment amount must be at least $1.</p>');
}
else {
amount = amount * 100;
handler.open({
amount: Math.round(amount)
})
}
});
// Close Checkout on page navigation
$(window).on('popstate', function() {
handler.close();
});
</script>
<% include partials/indexScripts %>
serverside (payment.js)
router.post("/", (req, res) => {
var amount = req.body.amount;
var object;
var ARef = admin.database().ref("ref");
var ARefList;
amount = amount * 100;
var object = {
amount: amount,
email: email,
inversedTimeStamp: now
}
stripe.customers.create({
email: req.body.stripeEmail,
source: req.body.stripeToken
})
.then(customer =>
stripe.charges.create({
amount: amount,
description: "desc",
currency: "usd",
customer: customer.id
})
)
.then(charge =>
ARef.transaction(function(dbAmount){
if (!dbAmount) {
dbAmount = 0;
}
dbAmount = dbAmount + amount/100;
return dbAmount;
})
)
.then( () =>
ARef.push(object)
)
.then ( () =>
ARefList.push(object)
)
.then( () =>
res.render("received",{amount:amount/100})
);
});
Thank you to "pksk321" from the freenode IRC #stripe for helping me with this !
Apparently, all that was needed was to add bitcoin: true to the handler, like so :
clientside
var handler = StripeCheckout.configure({
key: 'key',
locale: 'auto',
name: 'website',
description: 'Secure Payment',
bitcoin: true,
token: function(token) {
$('#stripeToken').val(token.id);
$("#stripeEmail").val(token.email);
$('form').submit();
}
});
Having a warm time trying to charge a card in Meteor. The error I get is: Exception while invoking method 'chargeCard' Error: Match error: Expected string, got object. I do get the modal where I typed in the email and card number but after pressing the pay button, in terminal I get the error message.
How to call the charge function properly? I cant find any tutorial that matches closely the way I implement it.
The setup is very basic. I also have jquery installed.
Template:
<template name="hello">
<form id="myForm">
<input type="text" id="amount" name="amount"/>
<input type="hidden" id="stripeToken" name="stripeToken"/>
<input type="hidden" id="stripeEmail" name="stripeEmail"/>
</form>
<hr>
<button id="customButton">Pay</button>
</template>
js:
if (Meteor.isClient) {
Template.hello.helpers({
});
Template.hello.events({
'click button': function (e) {
e.preventDefault();
var handler = StripeCheckout.configure({
key: 'pk_test_rand',
token: function(token) {
$("#stripeToken").val(token.id);
$("#stripeEmail").val(token.email);
$("#myForm").submit();
Meteor.call('chargeCard', token); // this seem not right?
}
});
// Showing the pop up Stripe dialog
var amount = $("#amount").val() *100;
// Open Checkout with further options
handler.open({
name: 'Demo Site',
description: '2 widgets ($20.00)',
amount: amount
});
// Close Checkout on page navigation
$(window).on('popstate', function() {
handler.close();
});
}
});
Meteor.startup(function(){
$.getScript('https://checkout.stripe.com/checkout.js', function(){
// script has loaded
});
});
}
if (Meteor.isServer) {
Meteor.methods({
'chargeCard': function(stripeToken) {
check(stripeToken, String);
var Stripe = StripeAPI('sk_test_rand');
Stripe.charges.create({
source: stripeToken,
amount: 5000, // this is equivalent to $50
currency: 'usd'
}, function(err, charge) {
console.log(err, charge);
});
}
});
}
It seems you're passing the whole token object:
Meteor.call('chargeCard', token);
But your chargeCard() method expects a string:
check(stripeToken, String);
So you need to either pass only the token id:
Meteor.call('chargeCard', token.id);
or change your chargeCard() method to expect and use the whole token object:
Meteor.methods({
'chargeCard': function(stripeToken) {
check(stripeToken, Object);
var Stripe = StripeAPI('sk_test_rand');
Stripe.charges.create({
source: stripeToken.id,
...