2025, Oct 16 23:16

Как в Stripe Basil получить confirmation_secret для подписки вместо PaymentIntent

В Stripe Basil latest_invoice.payment_intent больше нет. Узнайте, как получать confirmation_secret из Invoice при создании подписки и передать на фронтенд.

При создании подписки в Stripe и попытке подтвердить первичный платеж на фронтенде многие разработчики получают client_secret из PaymentIntent через первый счет. Если вы расширяете latest_invoice.payment_intent и при этом все равно ловите AttributeError на payment_intent, значит, вы наткнулись на недавнее ломающее изменение.

Пример, из-за которого возникает ошибка

Подписка создается с payment_behavior, установленным в default_incomplete, и с расширением, нацеленным на PaymentIntent в последнем счете. Доступ к payment_intent.client_secret в таком случае приводит к ошибке.

import stripe
stripe.api_key = 'sk_test_...'
unit_price = 'price_...'
plan_sub = stripe.Subscription.create(
    customer=acct_user.id,
    items=[{'price': unit_price}],
    payment_behavior='default_incomplete',
    expand=['latest_invoice.payment_intent'],
)
secret_for_ui = plan_sub.latest_invoice.payment_intent.client_secret

Что на самом деле происходит и почему

Stripe представил крупное обновление API (Basil), которое меняет связь счетов с платежами. Библиотека stripe-python следует за последней версией API, поэтому при использовании актуального SDK вы автоматически работаете с новым интерфейсом. В Basil Stripe убрал прямую связь между Invoice и единичным PaymentIntent, чтобы поддержать несколько частичных оплат по одному счету. В результате latest_invoice.payment_intent больше не существует у заново созданных объектов даже при расширении, что и объясняет AttributeError.

Это изменение и план миграции описаны в журнале изменений Stripe. Вместо получения client_secret из PaymentIntent на счете теперь нужно считывать новый confirmation_secret напрямую из Invoice. Ознакомьтесь с общим журналом изменений по адресу docs.stripe.com/changelog и с конкретной записью об этом обновлении в журнале изменений Basil. Новое свойство задокументировано в Invoice.confirmation_secret.

Решение и как получить секрет для фронтенда

Запрашивайте confirmation_secret у Invoice вместо PaymentIntent. При создании подписки расширяйте latest_invoice.confirmation_secret, затем считайте его из возвращаемого объекта и передайте на фронтенд.

plan_sub = stripe.Subscription.create(
    customer=acct_user.id,
    items=[{'price': unit_price}],
    payment_behavior='default_incomplete',
    expand=['latest_invoice.confirmation_secret'],
)
ui_token = plan_sub.latest_invoice.confirmation_secret

Так вы получите токен, необходимый для завершения платежного потока на клиенте.

Почему это важно

Платежные сценарии по подпискам часто завязаны на самый первый платеж. Если ваш код предполагает наличие PaymentIntent внутри latest_invoice, он сломается на API Basil. Переход на confirmation_secret согласует интеграцию с поддержкой нескольких частичных оплат и предотвращает ошибки во время выполнения, сохраняя при этом рабочую логику подтверждения на фронтенде.

Вывод

Если вы создаете подписки с payment_behavior = default_incomplete и вам нужен секрет для подтверждения на стороне клиента, перестаньте расширять latest_invoice.payment_intent и начинайте расширять latest_invoice.confirmation_secret. Следите за журналом изменений Stripe, особенно за крупными версиями вроде Basil, чтобы заранее замечать ломающие обновления и поддерживать стабильность платежных потоков.

Статья основана на вопросе со StackOverflow от Br0k3nS0u1 и ответе от koopajah.