Stripe source.chargeable event with null properties like amount and currency - stripe-payments

Is it correct to charge a source based on the event data's amount and currency? Sometimes I receive events like:
{
"object": {
"id": "src_1Ch7qCIhY6Z3DMWts3HPpWoH",
"object": "source",
"amount": null,
"card": {
"exp_month": 2,
"exp_year": 2022,
"address_zip_check": "unchecked",
"brand": "Visa",
"card_automatically_updated": false,
"country": "US",
"cvc_check": "unchecked",
"fingerprint": "xGimquKE7Rnk7LK2",
"funding": "credit",
"last4": "3063",
"three_d_secure": "required",
"address_line1_check": null,
"tokenization_method": null,
"dynamic_last4": null
},
"client_secret": "src_client_secret_D7MZe67elxyyCGGAaUA1lCsS",
"created": 1529983660,
"currency": null,
"flow": "none",
"livemode": false,
"metadata": {
},
"owner": {
"address": {
"city": null,
"country": null,
"line1": null,
"line2": null,
"postal_code": "22222",
"state": null
},
"email": null,
"name": null,
"phone": null,
"verified_address": null,
"verified_email": null,
"verified_name": null,
"verified_phone": null
},
"statement_descriptor": null,
"status": "chargeable",
"type": "card",
"usage": "reusable"
},
"previous_attributes": null
}
Notice amount and currency are null. Why isit null even when I have set the amount and currency when creating the source? I also notice its sometimes set correctly. Should I be relying on this properties set? Or should I be storing them in my DB? And store this transaction ID from DB into the metadata of the source for example.
UPDATE
I realized that this event is called when my frontend creates a 3ds source.
stripe.createSource(card).then(function (result) {
console.log(result.source)
})
I am alittle confused, the docs did say
When creating a 3D Secure source, its status is most commonly first set to pending and cannot yet be used to create a charge. In some cases, a 3D Secure source’s status can be immediately set to chargeable. This can happen if the customer’s card has not yet been enrolled in 3D Secure.
But I am using the test card, 4000000000003063 which requires 3ds verification. Why is it immediately chargeable?
status: "chargeable"
type: "card"
usage: "reusable"

The source you are creating is a regular card source, which is distinct from a Three D Secure source. That card source itself is chargeable, but if you try to charge it you will see that it will be declined because the card requires 3DS.
If the card source indicates that Three D Secure is required, then you need to use it to create a 3DS source and proceed with charging that instead : https://stripe.com/docs/sources/three-d-secure#create-3ds-source

Related

What stripe payment charge information should be stored by the application?

When integrating stripe payments (or stripe connect), stripe returns a Stripe::Charge object to the application after a payment has been attempted.
What is best practice for storing this information, that is, what fields should the application store in its database?
I think at an absolute minimum, the application should store:
the payment's id (so it can be looked up in the future),
the payment's status (so the app can know if the payment went through)
the app should obviously record which purchase the payment corresponds to
But there are many other fields in the Stripe::Charge object which seem quite important. However, storing everything could simply be completely unnecessary (overkill).
Here is an example of a Stripe::Charge object returned after a payment intent has been created:
{
"id": "ch_1HwISYGtUKse83O9n9LJ5DK1",
"object": "charge",
"amount": 30000,
"amount_captured": 30000,
"amount_refunded": 0,
"application": null,
"application_fee": "fee_1HwISY2fgYVxT5fZTsciNPKg",
"application_fee_amount": 4500,
"balance_transaction": "txn_1HwISZGtUKse83O9kkrHTynB",
"billing_details": {"address":{"city":null,"country":null,"line1":null,"line2":null,"postal_code":"41234","state":null},"email":null,"name":"Ben Johnson","phone":null},
"calculated_statement_descriptor": "JOE SMITH",
"captured": true,
"created": 1607481078,
"currency": "usd",
"customer": null,
"description": null,
"destination": "acct_1HtSLp2fgYVxT5fZ",
"dispute": null,
"disputed": false,
"failure_code": null,
"failure_message": null,
"fraud_details": {},
"invoice": null,
"livemode": false,
"metadata": {},
"on_behalf_of": "acct_1HtSLp2fgYVxT5fZ",
"order": null,
"outcome": {"network_status":"approved_by_network","reason":null,"risk_level":"normal","risk_score":63,"seller_message":"Payment complete.","type":"authorized"},
"paid": true,
"payment_intent": "pi_1HwIQwGtUKse83O9R4k7NiUa",
"payment_method": "pm_1HwISXGtUKse83O9ua95HqYJ",
"payment_method_details": {"card":{"brand":"visa","checks":{"address_line1_check":null,"address_postal_code_check":"pass","cvc_check":"pass"},"country":"US","exp_month":12,"exp_year":2034,"fingerprint":"W0rYzPMfZtx74C5u","funding":"credit","installments":null,"last4":"4242","network":"visa","three_d_secure":null,"wallet":null},"type":"card"},
"receipt_email": null,
"receipt_number": null,
"receipt_url": "https://pay.stripe.com/receipts/acct_1HYHSFGtUKse83O9/ch_1HwISYGtUKse83O9n9LJ5DK1/rcpt_IXNCchkcmv9fndlQPRCjh4mEtdNtTn0",
"refunded": false,
"refunds": {"object":"list","data":[],"has_more":false,"total_count":0,"url":"/v1/charges/ch_1HwISYGtUKse83O9n9LJ5DK1/refunds"},
"review": null,
"shipping": null,
"source": null,
"source_transfer": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "succeeded",
"transfer": "tr_1HwISYGtUKse83O9q9ZEE4Gq",
"transfer_data": {"amount":null,"destination":"acct_1HtSLp2fgYVxT5fZ"},
"transfer_group": "group_pi_1HwIQwGtUKse83O9R4k7NiUa"
}
So the simple, practical question: out of the above info, which fields should be stored in the application's database?
This entirely depends on the needs of your application and there is no universal answer. You can store all of it, none of it, or select fields.
The id is a good place to start, sure. If you were using Customers, you might want to store the associated customer id too. If you were using destination charges, you might want to store the related account. If you wanted to do some custom accounting you might store the amount and the fees.
It depends. Store whatever you like.

Stripe: Get all the transactions involved in a payout paid event webhook

I am subscribing to the payout.paid event of stripe.
The payout object has the following object:
{
"id": "po_1H50scIkcSPJwVI7bFSQmBnV",
"object": "payout",
"amount": 1100,
"arrival_date": 1594782118,
"automatic": true,
"balance_transaction": "txn_1H2z37IkcSPJwVI7rVwkvfCT",
"created": 1594782118,
"currency": "usd",
"description": "STRIPE PAYOUT",
"destination": "ba_1H50scIkcSPJwVI7MshqFr6u",
"failure_balance_transaction": null,
"failure_code": null,
"failure_message": null,
"livemode": false,
"metadata": {},
"method": "standard",
"source_type": "card",
"statement_descriptor": null,
"status": "in_transit",
"type": "bank_account"
}
Ref: https://stripe.com/docs/api/payouts/object
I am able to get this event in my webhook but I am interested in getting the transactions "involved" in this Payout.
Let's say if the payout is of $100 and I have two products of $2 and $5 each, I need to determine how many of those transactions are there from each price.
Not able to find it in docs but from the UI we can do this by going to the individual payout from the payouts screen from the "export" button beside the transactions section header:
You'd use the "List all Balance Transactions" endpoint and specify the Payout ID there: https://stripe.com/docs/api/balance_transactions/list#balance_transaction_list-payout
That way you receive a list of all balance transactions that were a part of that specific Payout.

Zapier is binding data response from GET request?

I am trying to manipulate a response from GET request, but Zapier is binding all the response data. Please see the image. Is this true, or there are ways around this?
This is the response from Zapier's GET.
Please point me a correct direction.
Here is the raw version:
{
"data": [
{
"id": 19235266,
"text": "Start of chat (WhatsApp)",
"photo": null,
"coordinates": null,
"transport": "whatsapp",
"type": "from_client",
"read": true,
"created": "2018-03-22T08:52:31 UTC",
"audio": null,
"pdf": null,
"remote_id": null,
"recipient_status": null,
"operator_id": 8645,
"channel_id": 1524,
"dialog_id": 903974,
"client_id": 1704911
},
{
"id": 19235267,
"text": "Chat agent – Administrator",
"photo": null,
"coordinates": null,
"transport": "whatsapp",
"type": "system",
"read": true,
"created": "2018-03-22T08:52:31 UTC",
"audio": null,
"pdf": null,
"remote_id": null,
"recipient_status": null,
"operator_id": null,
"channel_id": 1524,
"dialog_id": 903974,
"client_id": 1704911
}
]
}
Thank you in advance.
David here, from the Zapier Platform team.
Luckily, the fix here is very simple. If you want access to the raw hook (instead of the way we process it) you should use the Catch Raw Hook trigger:
Then you'll get your full body as a string:
and you can do whatever you'd like with it. For example, I wrote a small code step to pull the id of the first item:
let j = JSON.parse(inputData.data)
return {emails: j.data}
Which worked as expected. Note that if you return an array from a code step, subsequent steps will happen for each item. Proceed with caution when processing a bunch of items.

how to prevent to customer to add same credit card

I am using stripe as my payment provider and storing encrypted credit card id in my db returned from stripe.
My question is that from GUI customer can add same card again. I see stripe do not prevent to add same card multiple time for same customer. Since stripe always generates different encrypted card id for same card so I can't use it to validate if same card is being added again.
How can stop customer to add same card again again.
Looks like I got that . I can use fingerprint returned in json response. I saw stripe dashboard and found that fingerprint is always same for same card which I was adding again again.
Here is json request and response to confirm
Request
{
"source": {
"number": "378282246310005",
"cvc": "123",
"address_line2": "4th Floor",
"address_line1": "140 2nd Street",
"address_country": "USA",
"name": "VIAY KUMAR",
"address_state": "CA",
"exp_month": 12,
"exp_year": 2015,
"address_zip": "94105",
"address_city": "San Francisco",
"object": "card"
}
}
Response
{
"id": "card_166H9rC8Y8JrMFgBh9GVsmNG",
"object": "card",
"status": null,
"exp_month": 12,
"exp_year": 2015,
"last4": "0005",
"country": "US",
"type": null,
"name": "VIAY KUMAR",
"customer": "cus_6IrxhfwXNyD1Uw",
"recipient": null,
"address_line1": "140 2nd Street",
"address_line2": "4th Floor",
"address_zip": "94105",
"address_city": "San Francisco",
"address_state": "CA",
"address_country": "USA",
"address_zip_check": "pass",
"address_line1_check": "pass",
"cvc_check": "pass",
"fingerprint": "TwjSA2KqPDhSMUvQ",
"brand": "American Express",
"funding": "credit"
}
added same card again and got different card id but same finger print :-)
Request
{
"source": {
"number": "378282246310005",
"cvc": "123",
"address_line2": "4th Floor",
"address_line1": "140 2nd Street",
"address_country": "USA",
"name": "VIAY KUMAR",
"address_state": "CA",
"exp_month": 12,
"exp_year": 2015,
"address_zip": "94105",
"address_city": "San Francisco",
"object": "card"
}
}
Response
{
"id": "card_166HKVC8Y8JrMFgBfvbHPgk2",
"object": "card",
"status": null,
"exp_month": 12,
"exp_year": 2015,
"last4": "0005",
"country": "US",
"type": null,
"name": "VIAY KUMAR",
"customer": "cus_6IrxhfwXNyD1Uw",
"recipient": null,
"address_line1": "140 2nd Street",
"address_line2": "4th Floor",
"address_zip": "94105",
"address_city": "San Francisco",
"address_state": "CA",
"address_country": "USA",
"address_zip_check": "pass",
"address_line1_check": "pass",
"cvc_check": "pass",
"fingerprint": "TwjSA2KqPDhSMUvQ",
"brand": "American Express",
"funding": "credit"
}
Thanks to Vijay for the above answer.
I've written the following Ruby code in my Rails app to check for this.
Replace the relevant #user.stripe_customer_id variable with your own.
# Retrieve the customer we're adding this token to
customer = Stripe::Customer.retrieve(#user.stripe_customer_id)
# Retrieve the token
token = Stripe::Token.retrieve(params[:stripeToken])
# The fingerprint of the card is stored in `card.fingerprint`
card_fingerprint = token.card.fingerprint
# Check if the card fingerprint submitted matches one of the customer's current sources
fingerprint_already_exists = customer.sources.any? {|source| source[:fingerprint] == card_fingerprint}
if fingerprint_already_exists
# You can do whatever you want here. I've personally set a flash message to let the user know this card is already on their account
flash[:warning] = "That card already exists on your account."
redirect_to user_path(#user) and return
end
# Continue adding the source as normal
customer.sources.create(source: params[:stripeToken])
# Anything else you want to do...
flash[:success] = "Your account has been updated."
redirect_to user_path(#user) and return
The fingerprint generated by Stripe is unique to each card. As taken from the docs:
fingerprint string
Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number, for example.
Assuming you already have a customer object at this point (either a new one or one to update), this will let you add a card and make it default, without duplicates:
// $customer = \Stripe\Customer::retrieve( $clicker->customer );
/**
* Add the card, but only if it does not exist. Make it default in any case.
**/
$token = \Stripe\Token::retrieve( $_POST['stripeToken'] );
$card = null;
/** Does this customer already have this card? If so, find it. **/
foreach ( $customer->sources['data'] as $source ) {
if ( $source['fingerprint'] == $token['card']->fingerprint ) {
$card = $source;
}
}
/** If not, add the new card to the customer **/
if ( is_null( $card ) ) {
$card = $customer->sources->create( array( 'source' => $_POST['stripeToken'] ) );
}
$customer->default_source = $card->id;
$customer->save();
You'd enclose this in the usual try/catch as exemplified by the docs.
That being said, from the point of view of the user, it will be better, if possible, to show them a list of their cards (last4 + expire date) and let them pick the one they'd like to charge – instead of asking for their info needlessly.

Is it not possible to get the birthday of a user with JSON WS in Liferay?

I am using Liferay for user management and an external application that communicates with Liferay using JSON Web services. When I call the web service /user/get-user-by-id
{
"agreedToTermsOfUse": false,
"comments": "",
"companyId": 10153,
"contactId": 16003,
"createDate": 1390552990000,
"defaultUser": false,
"emailAddress": "basketball#liferay.com",
"emailAddressVerified": false,
"facebookId": 0,
"failedLoginAttempts": 0,
"firstName": "Basketball1",
"graceLoginCount": 0,
"greeting": "Welcome Basketball1!",
"jobTitle": "",
"languageId": "en_US",
"lastFailedLoginDate": null,
"lastLoginDate": null,
"lastLoginIP": "",
"lastName": "",
"ldapServerId": -1,
"lockout": false,
"lockoutDate": null,
"loginDate": null,
"loginIP": "",
"middleName": "",
"modifiedDate": 1390992862465,
"openId": "",
"portraitId": 18708,
"reminderQueryAnswer": "",
"reminderQueryQuestion": "",
"screenName": "basketball1",
"status": 0,
"timeZoneId": "Europe/Paris",
"userId": 16002,
"uuid": "3ce789e0-4cb5-45bf-b57e-68c44ea3ec04"
}
And some information as birthday is missed. I see that also I can change the birthday using the web services /user/update-user but I cannot retrieve the original value. How can I get the birthday information? Is there any other method to obtain the missing data?
And... if I want to update any field of the user and in /user/update-user I MUST put the birthday and I cannot retrieve the old value... the birthday will be lost!
You can get the user birthday through contact service:
http://localhost:8080/api/jsonws/contact/get-contact/contact-id/10202
where id is the user-id

Resources