Многие онлайн-платформы, включая Apple Media Services и AWS, становятся удобнее за счет сохранения платежных реквизитов, таких как данные кредитных карт или единого платежного интерфейса, с возможностью автоматических платежей. Плата за услуги списывается через регулярные временные интервалы или по мере использования, упрощается процесс выставления счетов, обеспечивается непрерывное предоставление услуг.

Клиенты наслаждаются беспроблемным обслуживанием, продолжая получать услуги без необходимости каждый расчетный период оплачивать их вручную. Эта система автоматических платежей необходима для бизнеса, осуществляемого по модели подписки, или там, где плата взимается в зависимости от фактического использования. Так обеспечивается ритмичность финансовых операций  —  и пользователям удобнее, и компаниям эффективнее.

Продемонстрируем, как интегрировать этот функционал с помощью языка программирования Go и платежной платформы Stripe во фреймворке Gin.

Начнем с генерирования API-ключа Stripe на портале разработчиков Stripe:

Получив ключ, приступим к реализации. Создаем клиента и указываем его имя, электронную почту, адрес:

type StripeProvider struct {
SecretKey string
}
func (s *StripeProvider) CreateCustomer() (*stripe.Customer, error) {
stripe.Key = s.SecretKey
params := &stripe.CustomerParams{
Name: stripe.String("John Dey"),
Email: stripe.String("[email protected]"),
Address: &stripe.AddressParams{
Line1: stripe.String("1234 Elm St"),
City: stripe.String("Smalltown"),
PostalCode: stripe.String("12345"),
State: stripe.String("CA"),
Country: stripe.String("US"),
},
}
result, err := customer.New(params)
return result, nil
}

С помощью этого скрипта в Stripe создается клиент, взамен из Stripe получается идентификатор клиента customer_id, например cus_Aqro4nFfTo0E8v.

Получение идентификатора клиента важно для настройки автоматических платежей. Имея этот идентификатор, создаем сеанс оформления и оплаты заказа, где клиент выбирает предпочтительный способ оплаты.

Так, если выбрана карта, инициируется соответствующий сеанс оформления и оплаты:

func (s *StripeProvider) CreateCheckoutSession() (*stripe.CheckoutSession, error) {
stripe.Key = s.SecretKey
params := &stripe.CheckoutSessionParams{
SuccessURL: stripe.String("https://example.com/success"),
Mode: stripe.String("setup"),
Customer: stripe.String("cus_HKtmyFxyxPZQDm"),
PaymentMethodTypes: stripe.StringSlice([]string{
"card",
}),
}
result, err := session.New(params)
return result, nil
}

Клиенты перенаправляются на SuccessURL после того, как реквизиты их карты сохранены с помощью Stripe. В ответе содержатся различные данные, но на этом этапе включается только необходимая информация:

{
"data": {
"sessionId": "cs_test_c1vTIqOhhs9db05IFiZuanbTcHgboHu2aOLbpjsbVagkY08h4muUJ07Nmo",
"successUrl": "http://localhost:8088/session/successfull",
"saveInfoUrl": "https://checkout.stripe.com/c/pay/cs_test_c1vTIqOhhs9db05IFiZuanbTcHgboHu2aOLbpjsbVagkY08h4muUJ07Nmo#fidkdWxOYHwnPyd1blpxYHZxWjA0SnR3ZE5WT2JUfEN2ZmQ1RkJ2NGdddn10QUJNclUza3FfY2xffHxsVWdBT1ZiYWxLXUEzPTx%2FYWI1PXZqdXMyMlZsZ0liQ3ZoNHVHZkkktAZ013c0t1cm5NNTVhRGl2RHBDUycpJ2N3amhWYHdzYHcnP3F3cGApJ2lkfGpwcVF8dWAnPyd2bGtiaWBaZmppcGhrJyknYGtkZ2lgVWlkZmBtamlhYHd2Jz9xd3BgeCUl"
},
"message": "Customer checkout done successfully !!"
}

Теперь, нажимая на saveInfoUrl, клиенты перенаправляются на страницу сохранения реквизитов карты:

Основная сложность  —  определение в реальном времени, когда же клиент сохранил реквизиты карты? Эта проблема решается веб-хуками. Подписываемся на события из дашборда Stripe и указываем безопасный URL-адрес HTTPS, настраиваемый с помощью ngrok или другого хостингового сервиса, где реализуем логику веб-хука:

Здесь подписались на три события: charge.failed, charge.succeeded и setup_intent.succeeded. Когда пользователь сохраняет реквизиты карты, веб-хуком сразу обнаруживается событие setup_intent.succeeded.

Чтобы инициировать платеж, из логов веб-хука извлекается идентификатор payment_method, по которому после того, как в целевом способе платежа активировано поле OffSession, с пользователя списываются конкретные суммы.

Таким образом упрощаются повторяющиеся платежи и автоматические транзакции.

Вот как настраивается код:

func (s *StripeProvider) CreatePaymentIntent() (*stripe.PaymentIntent, error) {
stripe.Key = s.SecretKey // Допустим, «SecretKey» задан корректно
params := &stripe.PaymentIntentParams{
Amount: stripe.Int64(1000000), // Предполагая, что «Balance» из запроса — это сумма в центах
Currency: stripe.String("usd"), // Валюта «usd», то есть доллар
Confirm: stripe.Bool(true),
PaymentMethod: stripe.String("payment_method_id after saving card"),
PaymentMethodTypes: stripe.StringSlice(["card"]),
Customer: stripe.String(customer_id), // Пример идентификатора клиента из входных данных
OffSession: stripe.Bool(true),
ConfirmationMethod: stripe.String("automatic"),
Description: stripe.String("Example payment intent for invoice"), // Описание транзакции
Name: stripe.String("John Doe"),
Address: &stripe.AddressParams{
Line1: stripe.String("1234 Main Street"),
PostalCode: stripe.String("94105"),
City: stripe.String("San Francisco"),
State: stripe.String("CA"),
Country: stripe.String("US"),
},
},
}

result, err := paymentintent.New(params)
return result, err
}

Вызвав этот API и подписавшись на события charge.success и charge.failed, отслеживаем логи в дашборде Stripe. Если платеж успешен, на транзакции здесь отобразится статус succeeded, то есть средства списаны:

Чтобы взимать плату по мере использования услуг, для этого процесса планируются повторные запуски или настраиваются выполняемые с определенной периодичностью задания cron.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Rohit Singh: Automating Payments with Stripe and Golang: A Developer’s Guide

Предыдущая статьяИзучаем AndroidManifest.xml: <service> как подэлемент <application>
Следующая статьяТемная сторона однонаправленных архитектур Swift