Відкрити застосунок
Усі дописи

Зробіть банку для чайових на власному акаунті Stripe

Три виклики API дають хостовану сторінку «плати скільки хочеш» з Apple Pay і Google Pay — і жодного сервера. Ось уся збірка: обмежений ключ, дозволи, як читати чайові без вебхука, і чесна арифметика комісій, яку ніхто не друкує.

Вам потрібна банка для чайових. Вам не хочеться віддавати платформі 5 % вечора вуличного музиканта, і ви цілком спроможні поговорити з API. Тож питання не в тому, у якій банці зареєструватися, а в тому, скільки насправді треба збудувати.

Менше, ніж здається. У Stripe робоча відповідь — три виклики API: жодного сервера, жодного бекенда, жодного вебхук-ендпойнта. Решта цього допису — саме ця збірка, плюс дві речі, які всі роблять неправильно.

Уся хитрість — це Price «плати скільки хочеш»

У Stripe є режим ціни, де суму вводить сам фан. Він називається pay what you want — і це вся функціональність. Ви створюєте Product, чіпляєте до нього Price з custom_unit_amount[enabled]=true, а зверху вішаєте Payment Link.

# 1. те, що ви "продаєте"
curl https://api.stripe.com/v1/products \
  -u "$RK:" \
  -d name="Tips — Mira" \
  -d "metadata[managed_by]"=my-tip-jar

# 2. ціна, яку обирає фан
curl https://api.stripe.com/v1/prices \
  -u "$RK:" \
  -d product=prod_... \
  -d currency=eur \
  -d "custom_unit_amount[enabled]"=true \
  -d "custom_unit_amount[preset]"=500 \
  -d "custom_unit_amount[minimum]"=200

# 3. сторінка
curl https://api.stripe.com/v1/payment_links \
  -u "$RK:" \
  -d "line_items[0][price]"=price_... \
  -d "line_items[0][quantity]"=1 \
  -d submit_type=pay

Третій виклик повертає url. Цей URL і є вашою банкою для чайових. Це сторінка, яку хостить Stripe: PCI-сумісна без жодних зусиль з вашого боку, локалізована, і вона показує Apple Pay або Google Pay кожному фану, у чийому телефоні вони налаштовані — динамічні методи оплати вирішують це за вас, залежно від пристрою й країни. Ви не написали жодного фронтенду.

Закодуйте URL у QR-код будь-якою бібліотекою — це просто рядок — надрукуйте, приклейте до футляра. Код ніколи не протухає й не вказує на жоден ваш сервер, бо сервера у вас немає.

Два параметри, які варто знати:

  • custom_unit_amount[preset] — сума, з якою сторінка відкривається. 500 означає, що фан бачить уже вписані 5,00 € і може їх змінити. Це число робить для вашого середнього чайового більше, ніж будь-що інше на сторінці.
  • custom_unit_amount[minimum] — підлога. Поставте її. Причина — у розділі про комісії нижче, і це не похибка округлення.

Можна також збирати ім'я та повідомлення. Payment Links приймають до трьох custom_fields — так ви отримуєте «а від кого це було» без побудови форми:

  -d "custom_fields[0][key]"=nickname \
  -d "custom_fields[0][type]"=text \
  -d "custom_fields[0][label][type]"=custom \
  -d "custom_fields[0][label][custom]"="Ваше ім'я або нікнейм" \
  -d "custom_fields[0][optional]"=true

У Stripe є вимоги до прийому чайових і пожертв — прочитайте їх один раз. «Плати скільки хочеш» також не поєднується з іншими line items, знижками чи регулярними платежами. Для банки з чайовими нічого з цього не заважає.

Цю різницю варто розуміти правильно. Stripe формулює так: чайові дають за вже надані товар чи послугу, а пожертва має бути прив'язана до благодійної мети. Ви відіграли сет; чайові за нього й платять. Тому виклик вище надсилає submit_type=pay, а не donatedonate розмістив би ваше посилання на donate.stripe.com і надрукував би на кнопці Пожертвувати. Це інший бізнес, і такий, який Stripe перевіряє помітно суворіше.

Ключ: припустіть, що він витече, — і зробіть це нудним

Не кладіть секретний ключ (sk_live_…) на пристрій, який стоїть на сцені. Візьміть обмежений ключ (rk_live_…): ви обираєте дозвіл для кожного ресурсу окремо, а все, чого ви не обрали, лишається на None.

Для збірки вище повний перелік — п'ять рядків:

Ресурс Дозвіл Що це дає
Products Write створити Product
Prices Write створити Price «плати скільки хочеш»
Payment Links Write створити посилання
Checkout Sessions Read бачити чайові, що надійшли
Events Read стрічка наживо (наступний розділ)

Усе інше — Balance, Payouts, Refunds, Customers, PaymentIntents, увесь Connect — лишається на None.

А тепер зробіть вправу, заради якої це все й затіяно. О першій ночі ваш планшет зникає зі столика з мерчем. Що злодій зробить із ключем у кейчейні? Прочитає історію чайових і створить іще посилань на чайові у вашому акаунті. Оце й увесь радіус ураження. Він не побачить баланс, не запустить виплату, не оформить повернення на свою картку, не прочитає список клієнтів. Ви відкликаєте ключ із телефона в таксі дорогою додому — і пристрій гасне. З ваших грошей не зрушилося нічого.

Ця асиметрія — запис у банку для чайових і нуль доступу до грошей — єдина причина, чому безсерверний дизайн із власним ключем взагалі можна захищати. Це ж і причина, чому «Login with Stripe» тут не відповідь: OAuth потребує сервера розробника застосунку, щоб тримати ваш токен, а сервер — це саме те, чого ми не будуємо.

(Дивина, на яку ви натрапите: дозвіл Prices усередині зветься plan_write, тож повідомлення про помилку від Stripe називає scope, якого під такою назвою в дашборді немає. Ідеться про Prices.)

Читати чайові без вебхука

Тут більшість інструкцій зупиняється або хапається за вебхук — і саме тут сцена справді відрізняється від вебзастосунку.

Вебхук — це вхідний HTTP-запит. Планшет за мікрофонною стійкою не може його отримати. Він у гостьовому Wi-Fi закладу за NAT-ом, без публічної адреси, без TLS-сертифіката — і не має жодних підстав це все мати. Якщо піти шляхом вебхука, доведеться підняти сервер, який ловитиме події, і сокет, який штовхатиме їх на пристрій: бекенд, експлуатаційний тягар і місце, де тепер живуть імена ваших фанів. Ви щойно відбудували ту саму платформу, якої хотіли уникнути.

Тож тягніть, замість чекати, поки штовхнуть. Ендпойнт List all events у Stripe публічний, задокументований і повертає події від найновіших:

curl -G https://api.stripe.com/v1/events \
  -u "$RK:" \
  -d "types[]"=checkout.session.completed \
  -d "types[]"=checkout.session.async_payment_succeeded \
  -d ending_before=evt_ОСТАННЯ_ПОБАЧЕНА \
  -d limit=100

ending_before — це весь дизайн. Тримайте id найновішої обробленої події; кожне опитування просить усе строго новіше, і ви посуваєте курсор. Жодних часових міток, жодного розходження годинників, жодної дедуплікації за сумою. На першому опитуванні сету попросіть limit=1 без курсора, щоб зачепитися за те, що вже є, і не програти на саундчеку чайові сьогоднішнього ранку.

Далі фільтруйте те, що повернулося. Обидва типи подій можуть спрацювати для одного платежу, тож дедуплікуйте за id Checkout Session. Перевіряйте payment_status == "paid" — завершена сесія не обов'язково оплачена. І перевіряйте, що payment_link збігається з вашим посиланням, бо /v1/events працює на рівні всього акаунта й радо віддасть вам трафік від усього іншого, що цей акаунт Stripe робить.

Будьте чесні щодо компромісів, бо вони справжні:

  • Stripe рекомендує вебхуки. Опитування — не благословенний шлях; це задокументований ендпойнт, який ви застосовуєте свідомо. Напишіть про це в README і йдіть далі.
  • Події сягають 30 днів назад. Слова самого Stripe: «List events, going back up to 30 days.» Це стрічка наживо, а не ваша бухгалтерська книга. Ваша книга — це Checkout Sessions, а справжня — дашборд Stripe.
  • Стежте за квотою читань. Усі дивляться на ліміт на секунду (rate limits: 100 запитів/с у live) і ніхто — на інший: Stripe виділяє приблизно 500 запитів на читання на одну транзакцію за ковзні 30 днів, з підлогою 10 000 читань на місяць. Опитуйте раз на 4 секунди — і тригодинний сет це ~2 700 читань. Чотири довгі концерти на місяць, і ви на підлозі. Чайові докуповують запас у міру надходження, але той, хто опитує щосекунди, бо «так жвавіше», знайде стелю. Чотири секунди — не лінива цифра; це та цифра.

Ось чесна форма справи: опитування коштує вам кількох тисяч GET-запитів і купує видалення цілого бекенда.

Арифметика комісій, зроблена як слід

Платформа, що рекламує 0 %, не є безкоштовною — і це теж. Власна комісія Stripe застосовується до кожного чайового, і Stripe виставляє її вам напряму. Сьогодні, за цінами Stripe в євро, стандартна картка ЄЕЗ коштує 1,5 % + 0,25 €. Преміальні картки ЄЕЗ — 1,9 % + 0,25 €, британські — 2,5 % + 0,25 €, усе інше — 3,25 % + 0,25 € плюс іще 2 %, якщо потрібна конвертація валюти. (У США це 2,9 % + 0,30 $, що гірше саме з наведеної нижче причини.)

Проблема не у відсотку. Проблема — у двадцяти п'яти центах.

Чайові Stripe бере Артист лишає собі Реальна частка
2 € 0,28 € 1,72 € 14,0 %
5 € 0,33 € 4,67 € 6,5 %
10 € 0,40 € 9,60 € 4,0 %
20 € 0,55 € 19,45 € 2,8 %
50 € 1,00 € 49,00 € 2,0 %

Фіксована комісія — це відсоток у масці, і на малих сумах маска сповзає. Ті самі 0,25 €, невидимі на чайових у 50 €, з'їдають одну восьму чайових у 2 €. Чайові малі за природою — саме це й робить їх чайовими — тож це не крайній випадок, а медіанний.

Саме тому ви ставите custom_unit_amount[minimum]. Десь коло 2 € транзакція перестає бути вартою обробки; картковий чайовий у 0,50 € надійде як 0,24 € і коштуватиме Stripe більше на переміщення, ніж він вартий. Обирайте підлогу свідомо, а не відкривайте її під час першої виплати.

І зверніть увагу, що це робить із порівнянням, з якого ви почали. Платформа, яка бере 0 % понад Stripe, бере 0 % понад оце. Їхні 0 % справжні — і це 0 % від того, що лишив процесинг. Нічия карткова рейка не безкоштовна: чесне формулювання — «жодної частки понад ту, що бере процесинг», і хто заявляє більше, той або бреше, або не використовує картки.

Що ви маєте тепер — і чого не маєте

Три виклики API і QR-код — і справжня банка для чайових: хостована, PCI-сумісна, Apple Pay, Google Pay, чайові падають на ваш власний баланс Stripe за вашим власним графіком виплат, і жодного сервера в дорозі. Для багатьох це щиро й буде кінцем проєкту, і ви цілком можете спинитися тут і випустити це.

Чого у вас немає — то це сцени. У вас є сторінка оплати. Між ними стоять нудні речі: цикл опитування з курсором і бекофом, екран, який бачить публіка, з ціллю й останнім повідомленням, місце для ключа, яке не зветься localStorage, блокування, щоб чужий не тицяв у планшет між сетами, і шар із тисячі дрібних рішень про те, що робити, коли Wi-Fi закладу падає посеред сету.

Саме цим і є live.tips — точнісінько ця архітектура, доведена до кінця, під ліцензією MIT. Обмежений ключ із тими п'ятьма дозволами, курсорний цикл на /v1/events, створення Product/Price/Payment Link — усе працює на пристрої артиста, проти його власного акаунта. У шляху Stripe немає сервера live.tips і ніде немає балансу live.tips — про це ми написали окремо в як live.tips поводиться з грошима.

Читайте код, беріть звідти те, що потрібно, або просто користуйтеся. Суть цього допису в тому, що архітектура — не таємниця й не складність: Stripe захостить вашу банку для чайових безкоштовно, а обмежений ключ плюс цикл опитування — це все, що стоїть між артистом і його власними грошима. Нам більше хочеться, щоб ви це знали, ніж щоб ви десь реєструвалися.

Усі дописи