UPDATED I built a pricing page that uses Stripe Checkout to use both a One-Time payment button for product 1 and a Subscription payment button for product 2.
My goal is to redirect the one time payment button to Stripe Checkout with a one time payment, and separately redirect the subscription payment to a checkout with a recurring payment.
According to STRIPE this can be done using Subscription as the Mode in the CheckoutSession in create-checkout-session.php (sample project) :
The mode of the Checkout Session. Required when using prices or setup mode. Pass subscription if the Checkout Session includes at least one recurring item.
Contrary to the Stripe Docs the following line of code: 'mode' => 'subscription',
activates subscription payments ONLY, but it doesnt redirect one time payments. For one-time payments to work I must change it to: 'mode' => 'payment',
but then subscription payments don't work.
Here's the php code in question:
<?php
require_once 'shared.php';
$domain_url = $config['domain'];
// Create new Checkout Session for the order
// Other optional params include:
// [billing_address_collection] - to display billing address details on the page
// [customer] - if you have an existing Stripe Customer ID
// [payment_intent_data] - lets capture the payment later
// [customer_email] - lets you prefill the email input in the form
// For full details see https://stripe.com/docs/api/checkout/sessions/create
// ?session_id={CHECKOUT_SESSION_ID} means the redirect will have the session ID set as a query param
$checkout_session = \Stripe\Checkout\Session::create([
'success_url' => $domain_url . '/success.html?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => $domain_url . '/canceled.html',
'payment_method_types' => ['card'],
'mode' => 'subscription',
'line_items' => [[
'price' => $body->priceId,
'quantity' => 1,
]]
]);
echo json_encode(['sessionId' => $checkout_session['id']]);
And here's the javascript code:
// Create a Checkout Session with the selected plan ID
var createCheckoutSession = function(priceId) {
return fetch("./create-checkout-session.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
priceId: priceId
})
}).then(function(result) {
return result.json();
});
};
// Handle any errors returned from Checkout
var handleResult = function(result) {
if (result.error) {
var displayError = document.getElementById("error-message");
displayError.textContent = result.error.message;
}
};
/* Get your Stripe publishable key to initialize Stripe.js */
fetch("./config.php")
.then(function(result) {
return result.json();
})
.then(function(json) {
var publishableKey = json.publishableKey;
var subscriptionPriceId = json.subscriptionPrice;
var onetimePriceId = json.onetimePrice;
var stripe = Stripe(publishableKey);
// Setup event handler to create a Checkout Session when button is clicked
document
.getElementById("subscription-btn")
.addEventListener("click", function(evt) {
createCheckoutSession(subscriptionPriceId).then(function(data) {
// Call Stripe.js method to redirect to the new Checkout page
stripe
.redirectToCheckout({
sessionId: data.sessionId
})
.then(handleResult);
});
});
// Setup event handler to create a Checkout Session when button is clicked
document
.getElementById("onetime-btn")
.addEventListener("click", function(evt) {
createCheckoutSession(onetimePriceId).then(function(data) {
// Call Stripe.js method to redirect to the new Checkout page
stripe
.redirectToCheckout({
sessionId: data.sessionId
})
.then(handleResult);
});
});
});
Is it even possible to have both one time payments and recurring payments on the same page with Stripe Checkout? How can I accomplish this?
Update according to Bemn:
$checkout_session = \Stripe\Checkout\Session::create([
'success_url' => $domain_url . '/success.html?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => $domain_url . '/canceled.html',
'payment_method_types' => ['card'],
'mode' => $body->mode
'line_items' => [[
'price' => $body->price_xxx,
// For metered billing, do not pass quantity
'quantity' => 1,
]],
'line_items' => [[
'price' => $body->price_zzz,
// For metered billing, do not pass quantity
'quantity' => 1,
]]
]);
echo json_encode(['sessionId' => $checkout_session['id']]);
And the JS:
// Create a Checkout Session with the selected plan ID
var createCheckoutSession = function(priceId, mode) {
return fetch("./create-checkout-session.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
priceId: priceId,
mode: mode // <-- passing the mode, e.g. 'payment' or 'subscription'
})
}).then(function(result) {
return result.json();
});
};
And the HTML:
<div data-stripe-priceid="pricexxx" data-stripe-mode="payment" id="onetime-btn" class="bold mt-2 d-inline-block w-100-after-md max-width-xxs py-2 btn btn-secondary">Ore Time</div>
<div data-stripe-priceid="pricexxx" data-stripe-mode="subscription" id="subscription-btn" class="bold mt-2 d-inline-block w-100-after-md max-width-xxs py-2 btn btn-secondary">Ore Time</div>
$new_plan = \Stripe\Plan::create([ 'id' => $amount, 'product' => $product_id, 'nickname' => $amount / 100 . ' GBP per month', 'interval' => 'month', 'currency' => 'gbp', 'amount' => $amount, ]);
where$product_id
is taken from the Stripe dashboard. This was about 18 months ago though so not sure how current it is. – wkille$subscription = \Stripe\Subscription::create([ 'customer' => $customer->id, 'items' => [['plan' => $amount]], ]);
(nb. I named the plans according to the amount so I could easily check if a plan for a particular amount already existed). Not sure how helpful this is for you, it looks like you're using Stripe in a different way to how I did. I do suspect however that you need to look at 'products' and 'plans'. – wkille