Displaying a fake price in Stripe - stripe-payments

I'm using Stripe's Checkout.
There is nothing that prevent me (apart my honesty) to display a low price to the customer, and then charge a higher price without his consent.
Did I miss something ? Is that an industry standard ? I believe it's not.
Why the token did not contain the user validated amount ?
Is it only in test mode ?
Thank you.
For exemple, this works (in test mode at least). I can see the high amount in my dashboard.
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="my_key"
data-amount="10"
data-currency="eur">
</script>
Then in the server side :
$charge = \Stripe\Charge::create(array(
"amount" => 10000,
"currency" => "eur",
"source" => $_REQUEST['stripeToken'],
));

You didn't miss anything -- it's up to each merchant to correctly display the amount and currency that will be used when actually charging their customers.
Failing to do would very likely result in disputes and chargebacks from your customers, which in turn could lead to your Stripe account being closed.

Related

How to get default payment method from Stripe invoice?

I am listening to Stripe's invoice.payment_failed webhook with my web app and I would like to get the default_payment_method from each invoice but for some reason it always returns nothing but an empty array!
When I query for a Stripe invoice on the command line and expand on the default_payment_method like this...
Stripe::Invoice.retrieve('in_3K6dIY2KgYRkshw2LAzya63P', :expand => "default_payment_method")
...I also get empty arrays. This surprises me because all my Stripe customers do have a default payment method associated with them.
What am I missing here?
Thanks for any help.
There are three independent places a default payment method can be set. From more specific to less specific they go :
invoice.default_payment_method (which you are looking at)
subscription.default_payment_method
customer.invoice_settings.default_payment_method
Stripe charges the most specific one if it's set. When reading from the API, those values don't inherit from the level above, they can all be set individually, if they are not set explicitly then they are null. So that's why you see it as null on the Invoice level.
Instead you likely want to look at the Subscription object or the Customer object(and can leverage the expand feature for that), depending on how you built your integration and which one it sets.
Overall though, you probably actually want the PaymentMethod used in the invoice payment though? That would be from the last_payment_error.
inv = Stripe::Invoice.retrieve({
id: 'in_1K8iiKJoUivz182DMzSkuBgp',
expand: ["customer.invoice_settings.default_payment_method",
"subscription.default_payment_method",
"payment_intent"]
}
)
print("invoice : #{inv.default_payment_method} \n")
print("subscription : #{inv.subscription.default_payment_method} \n")
print("customer : #{inv.customer.invoice_settings.default_payment_method} \n")
print("failed charge : #{inv.payment_intent.last_payment_error.payment_method} \n")

How can I prevent duplicate charge using Stripe?

I'm using Stripe to allow my customer to save a credit card and pay invoices (that have a unique id). On payment, I use a form to send a POST request with the card id (provided by stripe) to my server, and the controller charges it. Then I marked the invoiced as payed on my side.
Turns out that if I double click my form's submit button quick enough, I send two POST request and the cards ends up being charged twice, because when the second POST request arrives on my server, the POST request from my server to Stripe API (from the first click) isn't finished, thus the invoice has not been marked as payed yet.
I'm considering disabling the form submit button after first click, but I feel there may be a cleaner way.
Is there on Stripe's side to prevent duplicating charges (maybe using my invoice id)? If not what would the best back-end method to do this on my side?
Disabling the form submission after the first click is definitely the easiest way to implement this.
Another approach is to use idempotent requests as documented here. The idea is that you pass a unique identifier when making a request to Stripe's API that ensures you can only run this transaction once. If you re-run the query with the exact same idempotency key you will get the original response from the first call which ensures you never have 2 charges created for the same "transaction" on your website.
yes idempotent request is correct way to implement this.
you can refer this here
https://stripe.com/docs/api#idempotent_requests
another simple solution which you can implement is use of state machine by keeping track of stripe api call.
As mentioned by other answers, you can use Idempotent Requests to prevent duplicate charges. Here's how I've implement it:
On checkout.php:
<?php
function rand_string( $length ) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return substr(str_shuffle($chars),0,$length);
}
$idempotency = rand_string(8);
?>
...
<form method="post" action="payment.php">
<input type="hidden" name="idempotency" id="idempotency" value="<?=$idempotency?>">
...
</form>
...
On payment.php:
<?php
$idempotency = preg_replace('/[^a-z\d]/im', '', $_POST['idempotency']);
...
try {
$charge = \Stripe\Charge::create(
["amount" => $price,
"currency" => $currency,
"description" => $invoiceid,
"customer" => $customer->id ],
["idempotency_key" => $idempotency,]);
}catch(Exception $e) {
$api_error = $e->getMessage();
}

Stripe: Create a Charge with Coupon

Could you guy please show me how to create a Stripe Charge which can apply the discount automatically.
I have a valid coupon code (expired in far future, forever use, discount $2).
I create a new Stripe user and assign that Coupon Code for him.
I make a Charge with that customer and some money says: amount = $10.
All the thing works. When I login to Stripe Dashboard, I still see the new user in the list and he is using that Coupon Code. However in the payment, he still pay me $10 instead of $8.
I would like to make a Charge with amount = $10, however Stripe will do discounting so the true Charge will pay $8 only.
$myCard = array(
'number' => '4242424242424242',
'exp_month' => 12,
'exp_year' => 16
);
$coupon = Coupon::retrieve('6868');
//Valid coupon
$stripe_customer = Customer::create(array(
'card' => $myCard,
'email' => 'cus#info.com',
'coupon' => $coupon
));
$charge = Charge::create(array(
'customer' => $stripe_customer->id,
'amount' => 1000,
'currency' => 'usd'
));
Stripe does not allow coupons/discounts for one time payments because you don't really need Stripe to handle your coupons for one-time payments.
You need coupons for subscriptions because Stripe generates a subscription's charges automatically, by itself, on its own schedule. That means your code has no opportunity to modify the amount of the charge itself. Instead, you have to modify the subscription, which then modifies the charges it generates in the future. Stripe offers three simple ways to do this: changing the plan, setting the account balance, and adding invoice items. However, none of them allow you to specify a percentage discount or apply a modification for more than just the next invoice but less than forever. Coupons fix that issue.
A one-time charge, on the other hand, is always generated by you, so you always have an opportunity to modify the amount of the charge yourself. The problem that coupons are trying to solve doesn't exist here, so they aren't offered as an option.
reference : click here

Find credit card by type and expiration date

According to this "Account Updater only works with Visa and Mastercard"
So I want to find customers whose cards are going to expire in the next month and are from a different type than Visa or Mastercard.
In the docs I see I can filter by expiration date, but nothing about cardType (it mentions cardholderName)
var stream = gateway.customer.search(function (search) {
search.creditCardExpirationDate().is("12/13");
});
Is there a way I can filter this in the api request or should I need to get all results and filter out Visa and Mastercard customers?
Thanks.
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
Both you and #michelem are correct: the current api doesn't expose a method for filtering customers based on whether they contain a specific type of card. Your approach of filtering the results based on the Payment method is the best approach.

Passing sever side zip/postcode to Stripe checkout

I am trying set up Stripe checkout so I can pass my server side customer zip/postcode to the Stripe checkout. It seems like it should be very simple but I cannot get it to work!
At it's simplest, the code I am using is:
<form action="charge.php" method="POST">
<script
src="https://checkout.stripe.com/v2/checkout.js" class="stripe-button"
data-key="pk_test_redacted"
data-amount="2000"
data-name="Demo Site"
data-description="2 widgets (£20.00)"
data-currency="gbp"
data-address_zip="NG15 6UR">
</script>
</form>
the transaction works fine but it does not pass the zip/postcode so that it can be AVS checked.
What am I doing wrong?
Edit:
So apparently you cannot pass address information using checkout.js - you can only get the form to require the address from the customer when they put their card details in using
data-address="true2"
As far as I can tell, this means I can either hassle the customer by getting them to add their address details when I already have them!
or I have to use stripe.js which means I have build my own form, make it look pretty, validate it etc. Not a massive thing but, when there is a form there that does everything I need but accept address form fields passed at form creation, it is a little annoying :-(
If anyone knows otherwise I would love to hear it but this info came from the #stripe irc channel so I think it is probably correct.
As said in the Edit, I did have to use stripe.js and make my own form. Shame this small omission means quite a bit of extra work - but still much better than Paypal's mess of APIs and documentation! Cheaper too.
Untested but there may be a solution as you can update a card before the charge , you are able to update the customers card from the $token that you pass to your backend processor in php for example:
$cu = Stripe_Customer::retrieve($customer->id);
$card = $cu->cards->retrieve($token);
$card->address_city = $form['city'];
$card->address_line1 = $form['address_line_1'];
$card->address_line2 = $form['address_line_2'];
$card->address_state = $form['county'];
$card->address_country = "United Kingdom";
$card->address_zip = $form['postcode'];
Then take the charge
$charge = Stripe_Charge::create(array(
'customer' => $customer->id, etc...

Resources