• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Stripe Payment Element: Restrict to “Card Only” and Show Saved Payment Methods (Undocumented Edge Case)

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
Problem:
Stripe’s Payment Element allows multiple payment types and shows a Saved tab for logged-in users with saved payment methods.
But if you want to restrict the Payment Element to “card” only (no ACH, no Link, etc.) and show the user’s saved cards, Stripe doesn’t officially document how to do it.

The issue:

  • Using a SetupIntent with payment_method_types: ['card'] restricts to card, but the Saved tab won’t appear.
  • Using a CustomerSession enables the Saved tab, but it shows all your enabled payment methods, not just cards.
The Solution (SetupIntent + CustomerSession Hack)

  1. Create a SetupIntent for your customer with payment_method_types: ['card'].
  2. Also create a CustomerSession for that customer.
  3. Initialize the Payment Element with both the SetupIntent’s clientSecret and the CustomerSession’s customerSessionClientSecret.

Result:

  • Only “Card” is available for new payment methods.
  • The Saved tab appears with any saved cards.
Image description


Laravel Example



Route (web.php):


Route::get('/stripe-element-test', function () {
Stripe::setApiKey(config('services.stripe.secret'));
Stripe::setApiVersion('2024-06-20');

$user = auth()->user();
$isLoggedIn = !is_null($user);
$stripeCustomerId = ($isLoggedIn && $user->stripe_customer_id) ? $user->stripe_customer_id : null;

// Create SetupIntent for 'card' only
$setupIntentParams = [
'usage' => 'off_session',
'payment_method_types' => ['card'],
'payment_method_options' => [
'card' => ['request_three_d_secure' => 'automatic'],
],
];

// Attach customer only if available
if ($stripeCustomerId) {
$setupIntentParams['customer'] = $stripeCustomerId;
}

$setupIntent = SetupIntent::create($setupIntentParams);

$customerSessionClientSecret = null;
if ($stripeCustomerId) {
$customerSession = CustomerSession::create([
'customer' => $stripeCustomerId,
'components' => [
'payment_element' => [
'enabled' => true,
'features' => [
'payment_method_redisplay' => 'enabled',
'payment_method_save' => 'enabled',
'payment_method_save_usage' => 'off_session',
'payment_method_remove' => 'disabled',
],
],
],
]);
$customerSessionClientSecret = $customerSession->client_secret;
}

return View::make('stripe-test', [
'stripePublishableKey' => config('services.stripe.key'),
'setupIntentClientSecret' => $setupIntent->client_secret,
'customerSessionClientSecret' => $customerSessionClientSecret, // null for guest
]);
});

View (resources/views/stripe-test.blade.php):


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Stripe Payment Element Test – Card Only w/ Saved Methods</title>
<script src="

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

"></script>
<style>
body { font-family: sans-serif; margin: 40px; }
#payment-element { margin-bottom: 20px; }
button { padding: 10px 20px; background: #6772e5; color: #fff; border: none; border-radius: 5px; cursor: pointer; }
button:disabled { background: #aaa; }
#error-message { color: red; margin-top: 12px; }
#success-message { color: green; margin-top: 12px; }
</style>
</head>
<body>
<h2>Stripe Payment Element Test<br><small>(Card Only, Shows Saved Cards if logged in)</small></h2>
<form id="payment-form">
<div id="payment-element"></div>
<button id="submit-button" type="submit">Confirm Card</button>
<div id="error-message"></div>
<div id="success-message"></div>
</form>
<script>
const stripe = Stripe(@json($stripePublishableKey));
let elements;
let setupIntentClientSecret = @json($setupIntentClientSecret);
let customerSessionClientSecret = @json($customerSessionClientSecret);

const elementsOptions = {
appearance: {theme: 'stripe'},
loader: 'always'
};

if (setupIntentClientSecret) elementsOptions.clientSecret = setupIntentClientSecret;
if (customerSessionClientSecret) elementsOptions.customerSessionClientSecret = customerSessionClientSecret;

elements = stripe.elements(elementsOptions);

const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');

const form = document.getElementById('payment-form');
const submitButton = document.getElementById('submit-button');
const errorDiv = document.getElementById('error-message');
const successDiv = document.getElementById('success-message');

form.addEventListener('submit', async (event) => {
event.preventDefault();
errorDiv.textContent = '';
successDiv.textContent = '';
submitButton.disabled = true;

const {error, setupIntent} = await stripe.confirmSetup({
elements,
clientSecret: setupIntentClientSecret,
confirmParams: { return_url: window.location.href },
redirect: 'if_required'
});

if (error) {
errorDiv.textContent = error.message || 'Unexpected error.';
submitButton.disabled = false;
} else if (setupIntent && setupIntent.status === 'succeeded') {
successDiv.textContent = 'Setup succeeded! Payment Method ID: ' + setupIntent.payment_method;
} else {
errorDiv.textContent = 'Setup did not succeed. Status: ' + (setupIntent ? setupIntent.status : 'unknown');
submitButton.disabled = false;
}
});
</script>
</body>
</html>

Bonus:
This works for ACH or any payment method you might need to isolate in certain scenarios. IE, If you use ['us_bank_account'] for payment_method_types, users will see and be able to select their saved bank accounts.

Summary:
No official Stripe docs for this, but combining a SetupIntent (to restrict methods) and a CustomerSession (to show saved methods) gets you a Payment Element limited to card only, with the Saved tab.
Use at your own risk—Stripe could change this behavior, but it works today.

Hope someone finds this useful.
Cheers!


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу