I have a stripe standalone account that is activated and is accepting live transactions and connected to a platform stripe account. I am giving below the code I am using for accepting live payments.
\Stripe\Stripe::setApiKey("LIVE_PLATFORM_API_KEY");
$strtok = \Stripe\Token::create(
array(
"card" => array(
"number" => $cardnumber,
"exp_month" => $cardexpmonth,
"exp_year" => $cardexpyear,
"cvc" => $creditcardcvv
)
),
array('stripe_account' => "live_account_header")
);
$strtoken = $strtok->id;
$charge = \Stripe\Charge::create(array(
'amount' => $amts,
'currency' => 'usd',
'application_fee' => $appfee,
'source' => $strtoken
), array('stripe_account' => "live_account_header"));
I want to set up a debug mode in my code that will use the stripe test keys to accept test transactions even though both the stripe standalone and platform accounts are activated and in the live mode. I want the stripe calls I should use when I am debugging instead of making live transactions. I mean how should I change the above code and use test keys when I suddenly want to make a test transaction instead of a live one even though both the platform and the stand alone account are activated and live?
Whether a transaction is processed in test mode or live mode depends entirely on which set of API keys you use. If you use your test API keys, the transaction will be processed in test mode. If you use your live API keys, the transaction will be processed in live mode.
So what you need to do is decide which set of keys you're going to use based on some condition that you can trigger.
Basically, you'd need to replace this:
\Stripe\Stripe::setApiKey("LIVE_PLATFORM_API_KEY");
with something like this:
if ($test_condition) {
\Stripe\Stripe::setApiKey("TEST_PLATFORM_API_KEY");
} else {
\Stripe\Stripe::setApiKey("LIVE_PLATFORM_API_KEY");
}
Keep in mind that you also need to use your test publishable key in your frontend code (for creating tokens with Checkout or Elements) -- trying to create a charge in test mode if the token was created with a live key will not work.
In the sample code you provided, you're creating the token from your backend code (via \Stripe\Token::create(...)). This means that your server is directly providing the card data. This is fine when testing, but in live mode, tokens should always be created frontend-side, via Checkout or Elements. Otherwise, you would no longer be eligible for PCI SAQ A and would need to get your solution audited for PCI compliance.
Related
is there an api on shopify where I can see real time when data changes ? Maybe I have a node server and I use sockets to see when anyone has bought anything from my shop that I get a notification via nodejs on my backend. is it possible ? a few websites has this, they offers you to sell on their site and you can see real time changes data when anything was bought
Yes, you can subscribe to multiple Webhooks to get notified when a change occurs on your shop. Using the REST Admin API, available webhook event topics include:
orders/create: occurs whenever an order is created / someone buys from your shop.
orders/paid: occurs whenever an order is paid.
orders/fulfilled: occurs whenever an order is fulfilled.
orders/cancelled: occurs whenever an order is cancelled.
Use the /admin/api/2023-01/webhooks.json endpoint to subscribe to a webhook:
// Node.js - Session is built by the OAuth process
const webhook = new shopify.rest.Webhook({session: session});
webhook.topic = "orders/create";
webhook.address = "https://example.hostname.com/";
// format you want to receive the event data in
webhook.format = "json"; // or XML
// fields you want to receive
webhook.fields = [
"id",
"note"
];
await webhook.save({
update: true,
});
You can also use the GraphQL Admin API for the same purpose.
For my Amazon Pay integration with the NodeJs SDK, everything seems to be working great until I get to completeCheckoutSession. When I call completeCheckoutSession, the call is successful and appears to work, but I never receive a confirmation email stating the order has been processed and taking a look in seller central "Payment Status" is still marked as "Open". Moreover, I receive an email 24 hours later noting that the order was canceled.
Here is my code calling completeCheckoutSession with the NodeJs SDK:
const testPayClient = new Client.WebStoreClient(config)
const checkoutSessionId = requestBody.checkoutSessionId
const purchasePrice = requestBody.productInfo.price
const payload = {
chargeAmount: {
amount: `${purchasePrice}`,
currencyCode: 'USD'
}
}
let apiResponse = await testPayClient.completeCheckoutSession(checkoutSessionId, payload)
The price and checkoutSessionId are both coming from the front-end, and I have verified that the checkoutSessionId is the same as that being passed to getCheckoutSession and updateCheckoutSession.
Here is the data object that is returned if I console log apiResponse.data. I've removed null values for the sake of brevity. Additionally, the status code I receive is 200 if I were to log the entire "apiResponse" object.
{
checkoutSessionId: "not sure I should expose this, but it's here.",
statusDetails: {
state: 'Completed',
lastUpdatedTimestamp: '20211124T141939Z'
},
chargePermissionId: 'S01-9642704-9639513',
creationTimestamp: '20211124T141931Z',
}
Regarding that "state: 'Completed'", the docs note the following:
The Checkout Session moves to the Completed state after you call Complete Checkout Session if transaction processing was successful.
Is there something that I am missing about this call or doing incorrectly that my implementation is not moving the PaymentStatus from "Open" to something along the lines of "Succeeded"? I'd also like to point out that I am doing this all in Sandbox mode.
Thank you in advance for any guidance you can provide.
This issue is about the paymentIntent of the checkout session. According to the docs it has to be set to one of these values:
Confirm: Create a Charge Permission to authorize and capture funds at a later time
Authorize: Authorize funds immediately and capture at a later time
AuthorizeWithCapture: Authorize and capture funds immediately
When set to Confirm, you have to manually create a Charge to prevent the expiry, which you currently encounter. There are only very few use cases for using Confirm. In fact I have not seen any in real life until now.
Authorize is suitable, if you would like to have maximum control over the point of time to capture the amount. It also allows for an asynchronous flow, which increases the chances for a successful authorization by giving Amazon Pay up to 24h to decide.
AuthorizeWithCapture is the easiest and safest. It takes care of everything including the capture. If the checkout session is completed successfully, you will always have a complete payment.
Background:
Having obtained a paymentMethodId from the client with Stripe Elements, I am doing this on the server side:
stripe.paymentMethods.attach(..),
stripe.customers.update(...default_payment_method: ...).
stripe.subscriptions.create(..).
When additional action is required by 3DSecure, the subscription object (returned from create or fetched at a later date) includes a pending_setup_intent, which gives the info needed to resolve the intent (and i've got that working ok).
However if we run the subscriptions.create call when there aren't any payment methods on the Stripe Customer, the subscription object doesn't include a pending_setup_intent or anything else to indicate that the subscription doesn't have a way to pay.
Question:
Short of waiting for webhooks is there some way to have reasonably high confidence that the first payment on the subscription is likely to succeed, ie. there is a card, it's going to accept the payment (and yes, the 3DSecure stuff is sorted)?
Notes:
Although I'm not using trials on the subscription, the billing_cycle_anchor is in the future to provide a free period (basically a trial, but not explicitly making use of the stripe trial concept).
I'm using Stripe API version: 2015-03-24 (upgrading is a lower priority than resolving this)
Further clarification:
At the point we make the call to stripe.subscriptions.create(), the code is not aware of whether the paymentMethod was successfully attached and set as the default (I suppose we could check this, but my hope was that Stripe can handle that for us). For example when using the test card 4000000000000002 the payment method is not attached.
The call to stripe.subscriptions.create is of the form:
{
customer: stripeCustomerId,
billing_cycle_anchor: 1606946400,
cancel_at_period_end: undefined,
items: [{plan: "pro_annual"}],
prorate: false,
expand: ["pending_setup_intent", "pending_setup_intent.latest_attempt"]
}
I am implementing a stripe demo in which payment will be divided into multiple destination(multiple service provider).In that as i see when i use the below given array for multiple payment then it throws me an syntax error when web page is loaded.
//Create a Transfer to a connected account (later):
$transfer = \Stripe\Transfer::create([
'amount' => 7000,
'currency' => 'usd',
'destination' => 'HERE WILL BE STRIPE ACCOUNT ID',
'transfer_group' => 'ORDER_95',
]);
Here below it throws an error when web page is loaded :
Here below is the code of PHP and JS which i use to do payment.I does not have to disclose the stripe account id so that's why i have wrote "STRIPE ACCOUNT ID" over there.
1) PHP File
2) JS File
Thanks in advance!
It's impossible to know for sure but I suspect that either you've got an empty body in result. You should try just console.log()ing the response instead of trying to toString it, and you should also probably check (and log) the status.
https://developer.mozilla.org/en-US/docs/Web/API/Response
I am trying to implement a secure payment option with react-paypal-express-checkout...
but I saw that user can easily change the amount with chrome dev tools ... shouldn't I make the API request to paypal from my server and validate the amount with my DB? I didn't saw any option to do that with paypal...
here is my code:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import 'react-credit-cards/es/styles-compiled.css'
import './checkout.css';
import PaypalExpressBtn from 'react-paypal-express-checkout';
class CheckOut extends Component {
constructor(props) {
super(props);
this.state = {
amount: 40
}
}
render() {
const client = {
sandbox: 'XXXX',
production: 'Your-Production-Client-ID',
}
return (
<PaypalExpressBtn client={client} currency={'USD'} total={this.state.amount} />
);
}
}
export default connect(CheckOut);
Paypal allows both types of uses, from the client and from the server. I guess it's possible for the client to modify the request on their end to pay less. But, in the end, whatever your business is, you'll get an order and a payment. Just check if the payment is different than it should be and don't fulfil the order, make a refund.
If you want to save the trouble, then use the server option that makes the payment through your server.
In any case, like with any other payment method, I would recommend you take the time to implement it yourself following the great and well documented API provided by Paypal. They have a lot of examples and use cases, with code for the browser and the server.
Never trust values coming from the client side. You should absolutely validate the amount on the server-side.
As #jorbuedo said, you can create a server integration so the values are never exposed client side. Send a session ID or Order Number or something to your server, retrieve the order from your DB, and perform a redirect to PayPal to process the transaction server-side.
Alternatively, you can keep the client-side stuff you have, but then validate the transaction after it's been complete. You could use Instant Payment Notifications or the newer Webhooks to do this.
You could pass a custom variable into the paymentOptions property of <PaypalExpressButton ...>, and then use this value to validate the correct amount has been paid in IPN.
For example:
<PaypalExpressButton
client={client}
currency="USD"
total={this.state.amount}
paymentOptions={{
custom: this.props.sessionId
}}
/>
Then, as part of IPN, you can pull the Session ID out the DB, check the expected payment amount (which you'll need to store, or calculate based on the items/prices saved against the session ID) is the same as the payment amount Paypal provides (mc_gross for example). A full list of variables you get as part of IPN is available here.
There are no fees for using IPN. If you didn't want to build out this flow, then you'd have to manually validate every order that's made to ensure the amount is correct. If you're running something small, this might be an acceptable compromise.
Edit: Don't just send the expected amount as the Custom variable, and compare that to the mc_gross value, as this can also be changed using F12 or a browser extension. The value needs to be something opaque that you can translate server-side into something meaningful.
#jorbuedo and #Dave Salomon give great answers about Security and you should take them in to consideration.
However, If you really don't want to user to change your Component state and props, You can disable React Devtools with this hack.
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.emit = function() {};
}
Basically it mocks some methods of react-devtools and Devtool cannot find your component tree anyway.
This answer is only for disabling user to edit your components. This is not best solution for security)