Άνοιγμα εφαρμογής
Όλα τα άρθρα

Φτιάξτε ένα κουτί φιλοδωρημάτων στον δικό σας λογαριασμό Stripe

Τρεις κλήσεις API σάς δίνουν μια φιλοξενούμενη σελίδα «πλήρωσε όσο θέλεις» με Apple Pay και Google Pay — χωρίς κανέναν διακομιστή. Ιδού ολόκληρο το χτίσιμο: το περιορισμένο κλειδί, τα δικαιώματα, πώς διαβάζετε τα φιλοδωρήματα χωρίς webhook, και τα μαθηματικά των προμηθειών που δεν τυπώνει κανείς.

Θέλετε ένα κουτί φιλοδωρημάτων. Δεν θέλετε να δώσετε σε μια πλατφόρμα το 5 % της βραδιάς ενός πλανόδιου μουσικού, και τα καταφέρνετε μια χαρά με ένα API. Άρα το ερώτημα δεν είναι σε ποιο κουτί φιλοδωρημάτων να εγγραφώ, αλλά πόσα πρέπει πραγματικά να χτίσω.

Λιγότερα απ' όσα νομίζετε. Στο Stripe, η πρακτική απάντηση είναι τρεις κλήσεις API: κανένας διακομιστής, κανένα backend, κανένα endpoint για webhook. Το υπόλοιπο άρθρο είναι ακριβώς αυτό το χτίσιμο — συν τα δύο πράγματα που όλοι κάνουν λάθος.

Το κόλπο είναι ένα 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 σε κάθε θαυμαστή που τα έχει ρυθμισμένα στο κινητό του — οι δυναμικές μέθοδοι πληρωμής το αποφασίζουν για εσάς, ανάλογα με τη συσκευή και τη χώρα. Δεν γράψατε καθόλου frontend.

Κωδικοποιήστε το URL σε QR code με όποια βιβλιοθήκη θέλετε — είναι απλώς ένα string —, τυπώστε το, κολλήστε το στη θήκη. Ο κωδικός δεν λήγει ποτέ και δεν δείχνει σε κανέναν δικό σας διακομιστή, γιατί δεν έχετε.

Δύο παράμετροι που αξίζει να ξέρετε:

  • 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 και όχι donate — το donate θα φιλοξενούσε τον σύνδεσμό σας στο 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.

Τώρα κάντε την άσκηση που κάνει όλο αυτό να αξίζει. Στη μία τα ξημερώματα σας κλέβουν το tablet από τον πάγκο με τα merch. Τι μπορεί να κάνει ο κλέφτης με το κλειδί στο keychain; Να διαβάσει το ιστορικό φιλοδωρημάτων σας και να φτιάξει κι άλλους συνδέσμους φιλοδωρήματος στον λογαριασμό σας. Αυτή είναι όλη η ακτίνα της έκρηξης. Δεν βλέπει το υπόλοιπό σας, δεν μπορεί να πυροδοτήσει πληρωμή, δεν μπορεί να εκδώσει επιστροφή σε κάρτα που ελέγχει, δεν μπορεί να διαβάσει λίστα πελατών. Ανακαλείτε το κλειδί από το κινητό μέσα στο ταξί για το σπίτι και η συσκευή σβήνει. Από τα χρήματά σας δεν κουνήθηκε τίποτα.

Αυτή η ασυμμετρία — δικαίωμα εγγραφής στο κουτί, μηδενική πρόσβαση στα χρήματα — είναι ο μόνος λόγος για τον οποίο ένας σχεδιασμός χωρίς διακομιστή, με δικό σας κλειδί, στέκει καν. Είναι επίσης ο λόγος που το «Login with Stripe» δεν είναι η απάντηση εδώ: το OAuth χρειάζεται έναν διακομιστή του προγραμματιστή της εφαρμογής για να κρατά το token σας — και ο διακομιστής είναι ακριβώς αυτό που δεν χτίζουμε.

(Μια ιδιοτροπία που θα συναντήσετε: το δικαίωμα Prices ονομάζεται εσωτερικά plan_write, οπότε το μήνυμα σφάλματος του Stripe κατονομάζει ένα scope που στο dashboard δεν εμφανίζεται μ' αυτό το όνομα. Εννοεί το Prices.)

Διαβάζοντας τα φιλοδωρήματα χωρίς webhook

Εδώ τα περισσότερα κείμενα είτε σταματούν είτε πιάνουν ένα webhook — κι εδώ μια σκηνή διαφέρει πραγματικά από μια web εφαρμογή.

Ένα webhook είναι εισερχόμενο αίτημα HTTP. Ένα tablet πίσω από ένα μικροφωνικό στατό δεν μπορεί να λάβει τέτοιο. Κάθεται στο wi-fi επισκεπτών του μαγαζιού πίσω από NAT, δεν έχει δημόσια διεύθυνση, δεν έχει πιστοποιητικό TLS — και δεν έχει καμία δουλειά να τα έχει. Αν πάρετε τον δρόμο του webhook, πρέπει να στήσετε έναν διακομιστή που θα πιάνει τα events και ένα socket που θα τα σπρώχνει στη συσκευή: ένα backend, ένα λειτουργικό βάρος, κι ένα μέρος όπου τώρα κατοικούν τα ονόματα των θαυμαστών σας. Μόλις ξαναχτίσατε την πλατφόρμα που θέλατε να αποφύγετε.

Τραβήξτε λοιπόν, αντί να σας σπρώχνουν. Το endpoint List all events του Stripe είναι δημόσιο, τεκμηριωμένο, και επιστρέφει τα events με τα νεότερα πρώτα:

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_TO_TELEUTAIO_POU_EIDA \
  -d limit=100

Το ending_before είναι όλος ο σχεδιασμός. Κρατάτε το id του νεότερου event που επεξεργαστήκατε· κάθε δημοσκόπηση ζητά ό,τι είναι αυστηρά νεότερο, κι εσείς προωθείτε τον δείκτη. Χωρίς χρονοσφραγίδες, χωρίς απόκλιση ρολογιού, χωρίς αφαίρεση διπλότυπων βάσει ποσού. Στην πρώτη δημοσκόπηση ενός σετ, ζητήστε limit=1 χωρίς δείκτη ώστε να αγκυροβολήσετε σε ό,τι ήδη υπάρχει — αλλιώς στο soundcheck θα ξαναπαίξετε τα φιλοδωρήματα του σημερινού πρωινού.

Μετά φιλτράρετε ό,τι γυρίζει. Και οι δύο τύποι event μπορούν να πυροδοτηθούν για μία πληρωμή, οπότε αφαιρέστε τα διπλότυπα με βάση το id του Checkout Session. Ελέγξτε payment_status == "paid" — μια ολοκληρωμένη συνεδρία δεν είναι κατ' ανάγκη πληρωμένη. Κι ελέγξτε ότι το payment_link ταιριάζει με τον δικό σας σύνδεσμο, γιατί το /v1/events αφορά ολόκληρο τον λογαριασμό και θα σας παραδώσει πρόθυμα την κίνηση από ό,τι άλλο κάνει αυτός ο λογαριασμός Stripe.

Να είστε ειλικρινείς για τους συμβιβασμούς, γιατί είναι πραγματικοί:

  • Το Stripe συνιστά webhooks. Το polling δεν είναι ο ευλογημένος δρόμος· είναι ένα τεκμηριωμένο endpoint που το χρησιμοποιείτε συνειδητά. Γράψτε το στο README σας και προχωρήστε.
  • Τα events πάνε 30 ημέρες πίσω. Λόγια του ίδιου του Stripe: «List events, going back up to 30 days.» Αυτό είναι ζωντανή ροή, όχι λογιστικό βιβλίο. Το βιβλίο σας είναι τα Checkout Sessions — και το αληθινό είναι το dashboard του Stripe.
  • Προσοχή στο όριο αναγνώσεων. Όλοι κοιτούν το όριο ανά δευτερόλεπτο (rate limits: 100 αιτήματα/δευτ. σε live) και κανείς το άλλο: το Stripe κατανέμει περίπου 500 αιτήματα ανάγνωσης ανά συναλλαγή σε κυλιόμενο διάστημα 30 ημερών, με δάπεδο τις 10.000 αναγνώσεις τον μήνα. Δημοσκοπήστε κάθε 4 δευτερόλεπτα και ένα τρίωρο σετ κάνει ~2.700 αναγνώσεις. Τέσσερις μεγάλες εμφανίσεις τον μήνα και βρίσκεστε στο δάπεδο. Τα φιλοδωρήματα σας αγοράζουν περιθώριο καθώς φτάνουν — μα όποιος δημοσκοπεί κάθε δευτερόλεπτο επειδή του φάνηκε πιο ζωηρό, θα βρει την οροφή. Τα τέσσερα δευτερόλεπτα δεν είναι τεμπέλικος αριθμός· είναι ο αριθμός.

Αυτή είναι η ειλικρινής μορφή του πράγματος: το polling σας κοστίζει μερικές χιλιάδες GET και σας αγοράζει τη διαγραφή ενός ολόκληρου backend.

Τα μαθηματικά των προμηθειών, σωστά

Μια πλατφόρμα που διαφημίζει 0 % δεν είναι δωρεάν — ούτε κι αυτό εδώ. Η προμήθεια επεξεργασίας του ίδιου του Stripe ισχύει για κάθε φιλοδώρημα, και το Stripe τη χρεώνει απευθείας σ' εσάς. Σήμερα, σύμφωνα με τις τιμές του Stripe σε ευρώ, μια τυπική κάρτα ΕΟΧ κοστίζει 1,5 % + 0,25 €. Οι premium κάρτες ΕΟΧ 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 code — κι ένα αληθινό κουτί φιλοδωρημάτων: φιλοξενούμενο, συμβατό με PCI, Apple Pay, Google Pay, φιλοδωρήματα που προσγειώνονται στο δικό σας υπόλοιπο Stripe με το δικό σας πρόγραμμα πληρωμών, και κανέναν διακομιστή στη διαδρομή. Για πολλούς αυτό είναι ειλικρινά το τέλος του έργου, και μπορείτε άνετα να σταματήσετε εδώ και να το βγάλετε.

Αυτό που δεν έχετε είναι σκηνή. Έχετε μια σελίδα πληρωμής. Ανάμεσά τους στέκονται τα βαρετά: ο βρόχος δημοσκόπησης με τον δείκτη και το backoff του· μια οθόνη που μπορεί να δει το κοινό, με τον στόχο και το τελευταίο μήνυμα· ένα μέρος για το κλειδί που δεν λέγεται localStorage· ένα κλείδωμα ώστε να μη σκαλίζει κάποιος ξένος το tablet ανάμεσα στα σετ· και το στρώμα των χιλίων μικρών αποφάσεων για το τι γίνεται όταν πέσει το wi-fi του μαγαζιού στη μέση του σετ.

Αυτό ακριβώς είναι το live.tips — αυτή ακριβώς η αρχιτεκτονική, τελειωμένη, με άδεια MIT. Το περιορισμένο κλειδί με εκείνα τα πέντε δικαιώματα, ο βρόχος δείκτη πάνω στο /v1/events, η δημιουργία Product/Price/Payment Link — όλα να τρέχουν στη συσκευή του καλλιτέχνη, πάνω στον δικό του λογαριασμό. Δεν υπάρχει διακομιστής live.tips στη διαδρομή του Stripe ούτε υπόλοιπο live.tips πουθενά — αυτό το γράψαμε ξεχωριστά στο πώς χειρίζεται τα χρήματα το live.tips.

Διαβάστε τον κώδικα, πάρτε τα κομμάτια που θέλετε, ή απλώς χρησιμοποιήστε το. Το νόημα αυτού του άρθρου είναι ότι η αρχιτεκτονική δεν είναι ούτε μυστικό ούτε δύσκολη: το Stripe θα φιλοξενήσει το κουτί φιλοδωρημάτων σας δωρεάν, κι ένα περιορισμένο κλειδί συν ένας βρόχος δημοσκόπησης είναι το μόνο που στέκεται ανάμεσα σ' έναν καλλιτέχνη και τα δικά του χρήματα. Προτιμούμε να το ξέρετε παρά να εγγραφείτε οπουδήποτε.

Όλα τα άρθρα