#alex_best-practices
1 messages ยท Page 1 of 1 (latest)
๐ Welcome to your new thread!
โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.
โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.
๐ This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1397316976761638965
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.
- alex_best-practices, 59 minutes ago, 38 messages
Hi, my understanding is that as long as the requests are made on your account, it should have the same fingerprints. Are you seeing otherwise? Can you share the two requests so I can take a further look?
Hi pgskc, the fingerprints are consistent yes.
The concern is the following, we are trying to leave as much data on Stripe's side as possible, as such we are trying to avoid storing an array of card fingerprints on a user document, unless that's unavoidable.
So I've been looking at ways to take a payment method (from Tap to Pay) and using the PM to then do a lookup and get a customer ID.
That would enable us to identify a return user by customer ID.
Yeah, you can do that. We do recommend that you store the mapping on your end so you do not need to keep making GET calls as it won't scale since we have rate limits: https://docs.stripe.com/rate-limits
ok, these calls are happening as the result of a user interaction, so they shouldn't be all that frequent, but I'll review the limits now quickly to see if that's a fail-point.
Based on my understanding here, we'd be making at most 2 calls to stripe.getPaymentMethod() per interaction, and certainly not expecting more than 1 interaction per second.
Hi hi! Iโm going to be taking over for my colleague here. What is your concern around storing these on your side?
hi timebox, ok
the concern is maintaining a synchronized map of card fingerprints attached to a customer across our database and Stripe's. If we don't need to manage that mapping, I'd rather avoid it. I suppose I'm exploring the possibility of the stripe customer being the umbrella for all our stripe related data needs, so our application can store just that value and leave Stripe as the source of truth.
Ok, you could store things like this in the Customer's metadata.
I suppose some added context here is we deal with various payment providers including campus credential systems, so we've tried to abstract away the payment concerns.
I'll try to explain succinctly, and I think that will detail why metadata may not be sufficient in our case.
So we have two workflows, card present (Tap to Pay) and card not present (Stripe Elements).
I got it, no worries.
Ok, here's what I'd do:
ok
Wait ๐
Possible your customer would have more than one payment method in Stripe, or only ever one?
yeah that's the kicker, via either workflow, the customer could use effectively any number of payment methods.
so we are trying to account for the case where a customer adds a second payment method via Elements, and we are receiving either of those payment methods via Tap to Pay.
Ok. I think I have a solution. Gimme ... n seconds. ๐
lol ok no sweat
The direction I've been heading is to take the payment method contained in the setup-intent that we get back after Tap to Pay.
If that payment method has a customer, then I can lookup in our DB based on that customer ID, if it doesn't I create a new customer and attach the PM to the new customer.
But I got a bit hung up thinking about the top level payment method, the generated payment method, and how payment methods created from Elements would play into this.
As I'm talking that through, it may indeed be simpler to rely on the fingerprint as the ID that links them all.
Boom. Ok. Assuming less than 50 cards ๐คช you can just add each card as metadata on the Customer wth the fingerprint as the key, and ~anything as the value. Then you can use the Search API to search for metadata[$FINGERPRINT]:null and you'll get back the Customer(s) with that fingerprint.
Interesting, let me think about that for a minute.
I just created a test customer with a couple cards, and when I run the following, I get that Customer back:
curl -G https://api.stripe.com/v1/customers/search \
-u "sk_test_beepboopsecretsauce:" \
--data-urlencode query="metadata[\"FINGERPRINT_\"]:null"
(With non-silly values, obviously)
(Assuming less than 50 metadata entries; if you're using metadata for other purposes, that would reduce that limit since you only get 50 of 'em)
right, no we're not as of today using metadata nor are we expecting so many cards
but this solution still involves creating a distinct source of truth and the overhead of maintaining it
albeit it in this case the data lives on the customer itself
Wait, how are you doing this for other processors? Do they have a 'fingerprint' analog?
The other processors in question are campus credential systems, and they're all a little different. Primarily what we do is get the underlying user Id, which we can then use to effectuate transactions against the account, rather than any specific card. So I'm trying to achieve something similar here with Stripe.
Ooooo.
payment_method_details.card.fingerprint:"fp"
You can search for Fingerprint. Let me just test this too.
Actually, that's for Charge search, not Customer search. ๐ฆ
Ah ok
Oooo
But it includes the Customer ID (at least in the case where the Customer is known, I guess?)
But it would only work if there was a Charge.
How do you get the "underlying user Id" from the campus cred system(s)?
There are two ways to get that User ID typically, either the students authenticates with SSO, or we read a card number from a physical terminal and can do a lookup to find the student that owns that card.
Tell me more about that second part.
For some of the card providers, the card number is considered authoritative enough to get a student account. It's essentially a key.
But the cards are fairly rudimentary, they just expose a string.
Sorry what's a PAN?
Credit card number.
It's not a credit card, it's a campus card.
Ohhhhhhhhh
So the string on the card is basically just an ID.
So like a "gift card" give or take?
But it's assumed that the holder of the ID is the authenticated user, essentially. And an authorized partner can trade it for account info.
Or more like a Student ID?
And you use that ID to look up the details in a third party system, or in your system?
In the third party system. Of course we have to be certified and identify ourselves and so forth before we can get any info, but that's essentially how it works.
Now, we do also, in the same place as the stripe fingerprint, store that number for reference.
For sure. Ok, so you don't have to store that ID at all, just capture on the terminal, query the third party system, and then use the results of that as your 'payment source', right?
Yes effectively.
We do store it but technically don't have to, similarly to the fingerprint. The fingerprint has been handy for quickly recognizing repeat users with Tap to Pay.
And we could convert that field to an array and maintain a list of fingerprints, but yeah, we're back at the start and I'm looking for a more deterministic option.
Right, which is part of its purpose.
What's wrong with the approach you're using exactly?
So the product people now want to allow users to store X number of credit/debit/mobile wallet payment methods on their account.
In tandem, we want to recognize that user if they use the same PM with Tap to Pay.
Right, ok. What server-side language and database do you use?
nodejs/mongodb
Ok awesome. So swapping from a single value to an array should be pretty straightforward, right?
Yes, it's a viable option, for sure.
It's likely the "best" way to solve this.
payment_methods: [
"stripe:0Nef1NG3rprnt",
"stripe:0th3er1NG3rprnt",
"other_thingy:abc123studentId",
"other_thingy:def456studentId",
]
...or similiar.
yeah I mean, we already have different keys per payment provider thing, so we could go straight array with strings not a problem there.
I guess I'm really interested in a way to do this without relying on fingerprints, because it seems to me we go through the trouble of linking customers and payment methods, and it would be preferable if we could get our customer from a payment method.
Which I understand is possible.
You can't get from a Fingerprint to a Payment Method, because it's not 1:1.
No, but we should be able to get from a Payment Method to a customer?
If I add the same card for my sixteen kids, you'll get sixteen results searching for that card's fingerprint.
You can retrieve the Payment Method, and if it's associated with a Customer, it should show it: https://docs.stripe.com/api/payment_methods/retrieve
...but when someone taps, there's only a fingerprint, not a Payment Method, right?
When someone taps, we do get a payment method.
Be aware you can get more than one if that card's been used by more than one Customer - like, fingerprint is not a unique key for ( fingerprint, payment_method )
We create a setup intent (no customer), the user taps, we attach that payment method to the setup intent.
Then, (currently) if we match on the PM's fingerprint in our DB, we don't create a new customer. If we don't match, we create a new customer and attach the PM to that customer.
What I'd ideally like to do, is forget about the fingerprint, lookup against Stripe to see if that PM has a customer attached (meaning we have connected this PM previously). If none, create one and attach.
That PM will never have a Customer attached unless you attach it to a Customer. Fingerprint (and therefore card) is not a unique key for ( fingerprint, payment_method ).
What the docs tell us to do, is to use the PM.generated_card, since that is a card that can be charged off-session. so that's the one we link.
What I'm now trying to understand is what is the relationship between a generated card, and a regular card that might be inputted say via Stripe elements.
unless you attach it to a Customer.
Correct, we are explicitly attaching it to a customer, though.
To which Customer?
If we receive a card tap with a fingerprint that doesn't match an existing user in our DB, we create a new customer, attach the PM from the Tap to this new customer, and save the customer ID (and fingerprint) to our user.
Right, ok.
You can't remove fingerprint from this flow, or it won't work. The PM ID that is created from today's tap will not be the same as the PM ID that you stored yesterday.
Sure, but it's not the PM ID we store, it's the customer ID.
Ok, I guess I'm confused what you're trying to accomplish, because I thought you were trying to stop storing the fingerprint.
lol, yes, we are looking to not rely on the fingerprint, and rely on the customer for everything, essentially.
You cannot get from a tap to one or more Stripe Customers without the fingerprint.
Fingerprint is effectively a ( card_number , stripe_account ) ID, and so could exist n times on m Customers in your Stripe Account.
Hm, but it seems I can go from: SetupIntent -> LastAttempt -> PaymentMethod -> Customer
If that SetupIntent is associated with a Customer, yes.
But unless you provided the Customer ID when creating the Tap to Pay Setup Intent (which makes no sense because you don't know the Customer yet), you would never have a Customer on that SetupIntent.
Maybe I didn't clarify but we use SetupIntents with Tap to Pay to setup future usage, so not using a Payment Intent, if that changes anything.
Right, the customer is not on the Setup Intent. We create the customer after, and attach the payment method to the customer.
Then my understanding is when the same payment method is used to confirm a future setup intent, we can use the PM to get an attached customer.
But maybe like you're saying, that PaymentMethod ID will not be consistent across interactions?
PhysicalCard + StripeAccount => Fingerprint
Fingerprint => [ PaymentMethod, PaymentMethod, ... ]
PaymentMethod => Customer
It will not.
OK then that's the piece I was missing
So what is the purpose of attaching the Payment Method to the customer?
The Customer is the thing that effectively allows reuse of the Payment Method. If you want to be able to reuse a Payment Method multiple times, it has to be owned by a Customer.
(if I remember correctly)
OK
so attaching it is really just there for later charging the customer
Like this step: https://docs.stripe.com/terminal/features/saving-payment-details/save-directly?terminal-sdk-platform=server-driven#submit-payment-method
Is about charging later, it doesn't help us with recognizing the payment method during a later interaction.
Correct.
So put differently, a payment method ID is ephemeral.
No, it's permanent - it just doesn't map 1:1 with a physical credit card.
Physical Card <> PaymentMethod is 1:*
No, actually it's *:*
No, I was right the first time. ๐
lol ok
One physical card can have ~many Payment Method objects - even in your own Stripe Account.
I see
I.e., the 4242424242424242 Stripe test card always has the same fingerprint when attached to any Customer in your Stripe Account.
right, but it can yield different payment method?
Correct.
If you add the (same) card to a Customer twice, you get two Payment Methods with two different IDs, but with the same Fingerprint.
ouf
ok, other mind bender for you since we're on a roll here. If I use Elements to input a card number, then use mobile wallet with the same underlying card, I'll get two fingerprints, correct? But those fingerprints will map to the ones I get during Tap to Pay?
lol ok
are you saying apple will yield a fingerprint different from google for the same card info?
They have something similar to the generated_card which is different from the underlying payment method - except Apple and Google don't surface the original details at all.
Correct.
ok wow, so a single card can easily yield 3 fingerprints
Apple, Google, "real card" => 3 different ... yes.
but, critically, if use a wallet with Stripe elements, then the same wallet with Tap to Pay, fingerprint =
In theory it should, yes.
(In practice, it most likely does but I've never tested it myself)