Can we update payment method for braintree subscription? - subscription

I'm new to braintree. Can we update payment method to an existing subscription. Is their any way to update payment method. So
user can change their cards for subscription ?
From braintree documentation will this work ?
$result = $gateway->subscription()->update('old_subscription_id', [
'id' => 'old_subscription_id',
'paymentMethodToken' => 'new_payment_method_token'
]);

Full disclosure, I work at Braintree. If you have any additional questions, contact Support
You can update an existing subscription to use any other payment method that is stored in your Vault. You can do this with an existing payment method, or by creating a new payment method with a paymentMethod()->create() API request.
With that said, the request you provided may work, but I recommend not including the id parameter, as that is reserved for setting a new subscription ID. The subscription ID you are hoping to edit will be placed in the first argument, as you've included in your code. You can simplify the request to look something more like this:
$result = $gateway->subscription()->update('old_subscription_id', [
'paymentMethodToken' => 'new_payment_method_token'
]);

Related

Firestore Security rules with payment form

I'm creating a raffle website. The user connects his wallet and pays for a raffle ticket. After the blockchain transaction confirmation, I add his raffle ticket in a collection in firestore.
It causes a security issue because if I allow the user to write to the raffle ticket collection in my firebase security rules, he could create his own tickets without paying.
I need tickets to be added to the database only if payment has been successfully made.
I don't know how websites that have means of payment do it. Maybe firebase isn't a good solution ?
My project is in react/typescript.
You say you do the payment over the blockchain and I assume you use solidity as your smart contract language?
Why don't you emit an event in your smart contract?
You then listen for these events on a (seperate) server.
That updates your (firebase) database whenever an event was emitted.
(Untested) Sample Code:
How do you emit events in solidity? (raffle.sol)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Raffle {
event PaymentCompletion(address buyer, uint256 amountOfTickets);
function buyTickets() external payable {
emit PaymentCompletion(msg.sender, msg.value)
}
}
How do you listen to these events?
when using web3js:
const contract = new web3.eth.Contract(CONTRACT_ABI, CONTRACT_ADDRESS);
const lastBlock = await web3.eth.getBlockNumber()
// paymentEvents is an array containing the payments of the last 500 blocks.
const paymentEvents = await contract.getPastEvents(
'PaymentCompletion', // change if your looking for a different event
{ fromBlock: latestBlock - 500, toBlock: 'latest' }
);
now iterate through these events and put them into your database. You can also set up a subscription which notifies you whenever a new block was created, so you can check if new events were inside of the current block.
This is what it would look like if you add the first blockchain event to the firebase realtime database.
var db = admin.database();
var ref = db.ref("/payments");
// ...
ref.child("path/to/transaction").set({
buyer: paymentEvents[0].buyer,
amountOfTickets: paymentEvents[0].amountOfTickets,
// put the rest of your data here
}, (err) => {
if (err) {
console.error(err)
}
})
Alternatively (if you don't want to handle the payment on the blockchain) you could also take a look at stripe, it also has a firebase plugin for easy integration. (but I've never tried it out). However, imo using the blockchain for handling the payment would be the cleanest solution. (+ you don't have the handling fees stripe uses).
I hope I could give you some good clues! Firebase should be definitely suitable for this.

react-paypal-button-v2 returning the wrong order id

I was trying to debug a problem related to refunding Paypal orders (in a sandbox environment) using order IDs (which were stored previously). Every time I tried to perform a refund, the Paypal API would return an INVALID_RESOURCE_ID error, meaning that no such order existed. After much debugging, I have made a revelation with the initial process when I stored said order ID. The following method is how I am retrieving and storing said order id:
const onApprove = (data, actions) => {
// Redux method of saving checkout in backend with order ID via using data.orderID
dispatch(saveCheckout(data.orderID);
return actions.order.capture();
}
<PayPalButton
amount={totalPrice}
currency= "AUD"
createOrder={(data, actions) => createOrder(data, actions)}
onApprove={(data, actions) => onApprove(data, actions)}
options={{
clientId: "<placeholder>",
currency: "AUD"
}}
/>
I am using the recommended data.orderID from the docs and yet, upon inspecting the network tab, the following is shown:
{"id":"5RJ421191B663801G","intent":"CAPTURE","status":"COMPLETED","purchase_units":[{"reference_id":"default","amount":{"currency_code":"AUD","value":"24.00"},"payee":{"email_address":"sb-sg4zd7438633#business.example.com","merchant_id":"EJ7NSJGC6SRXQ"},"shipping":{"name":{"full_name":"John Doe"},"address":{"address_line_1":"1 Cheeseman Ave Brighton East","admin_area_2":"Melbourne","admin_area_1":"Victoria","postal_code":"3001","country_code":"AU"}},"payments":{"captures":[{"id":"7A2856455D561633D","status":"COMPLETED","amount":{"currency_code":"AUD","value":"24.00"},"final_capture":true,"seller_protection":{"status":"ELIGIBLE","dispute_categories":["ITEM_NOT_RECEIVED","UNAUTHORIZED_TRANSACTION"]},"create_time":"2021-10-11T00:40:58Z","update_time":"2021-10-11T00:40:58Z"}]}}],"payer":{"name":{"given_name":"John","surname":"Doe"},"email_address":"sb-432azn7439880#personal.example.com","payer_id":"KMEQSKCLCLUZ4","address":{"country_code":"AU"}},"create_time":"2021-10-11T00:40:48Z","update_time":"2021-10-11T00:40:58Z","links":[{"href":"https://api.sandbox.paypal.com/v2/checkout/orders/5RJ421191B663801G","rel":"self","method":"GET"}]}
The id saved by onApprove is 5RJ421191B663801G but there is another ID under captures and id which is 7A2856455D561633D. This is the actual order id I need to save in order to make the refund later on. However, I am struggling as to how I can retrieve this value as that id value seems to be only visible via the network. The objects returned via the onApprove and action.order.get() methods only return the first "false" id. Any advice would be greatly appreciated.
These are two separate types of IDs, the order ID (used only during buyer checkout approval), and the payment/transaction ID (which only exists after an order is captured, and is the one needed for any later refund or accounting purposes)
Since you are capturing on the client side with actions.order.capture(), this is where you would need to add a .then(function(data){ ... }) to do something with the capture data (particularly data.purchase_units[0].payments.captures[0].id). That is the id you would use for a refund.
In actual best practice, if anything important needs to be done with the capture id -- such as storing it in a database for reference -- you should not be creating and capturing orders on the client side, and instead calling a server-side integration where that database write will be performed.
Follow the Set up standard payments guide and make 2 routes on your server, one for 'Create Order' and one for 'Capture Order', documented here. Both routes should return only JSON data (no HTML or text). Inside the 2nd route, when the capture API is successful you should store its resulting payment details in your database (particularly the aforementioned purchase_units[0].payments.captures[0].id, which is the PayPal transaction ID) and perform any necessary business logic (such as sending confirmation emails or reserving product) immediately before forwarding your return JSON to the frontend caller.
Pair those 2 routes with the frontend approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
Or for react, use the official react-paypal-js

stripe paymentRequest with total amount 0$

when I'm trying to make payment with payment request button I need to set 0$ amount when creating payment intent for it, but I can't, cause for creating payment intent stripe requires min 0.50$. I need it cause I'm using it for metered subscription type and don't have to charge client when subscribing. I found solution to refund after successfully subscription, but I don't like it.
I'm creating payment_intent with this api
app.post('/api/client-secret', async (req, res) => {
try {
const { currency, amount } = req.body;
console.log(req.body)
const paymentIntent = await stripe.paymentIntents.create({
amount,
currency: 'usd',
payment_method_types: ['card'],
});
res.json({ clientSecret: paymentIntent.client_secret });
} catch (error) {
console.log("error1", error)
}
});
maybe there is other way or method to create client_secret for stripe.paymentRequest()
The payment_intent object has a field called capture_method. You can set this manual, in which case the payment is not immediately captured by stripe. Pay attention to the parenthesis:
(Not all payment methods support this)
On a different note, if this is a subscription, then why not use the subscription api or even better, sessions. I suggest sessions because it handles all sorts of issues that may arise during a transaction, and all you need to do is wait for the session to complete, and everything will be taken care of.
Also note that the price object (which represents the items you are selling) comes with a field called usage_type which allows you specify that the item is metered, so stripe can handle the billing for you if someone purchases that item.
The stripe api is vast and well documented, so I hope this answer helps you discover a solution quickly.
If you're not charging the user upfront, you should use SetupIntents to save and attach card details to the Customer for charging them in the future — when they’re offline : https://stripe.com/docs/payments/save-and-reuse

Getting a users mailbox current history Id

I'd like to start syncing a users mailbox going forward so I need the most recent historyId of the users mailbox. There doesn't seem to be a way to get this with one API call.
The gmail.users.history.list endpoint contains a historyId which seems to be what I need, from the docs:
historyId unsigned long The ID of the mailbox's current history record.
However to get a valid response from this endpoint you must provide a startHistoryId as a parameter.
The only alternative I see is to make a request to list the users messages, get the most recent history id from that, then make a request to gmail.users.history.list providing that historyid to get the most recent one.
Other ideas?
Did you check out https://developers.google.com/gmail/api/guides/sync ?
Depending on what your use-case is, to avoid races between your current state and when you start to forward sync, you'll need to provide an appropriate historyId. If there were a "get current history ID" then anything between your previous state and when you got those results would be lost. If you don't have any particular existing state (e.g. only want to get updates and don't care about anything before that) then you can use any historyId returned (e.g. on a message or thread) as you mention.
Small example for C# users (mentioned in comments by #EricDeFriez).
Nuget package Google.Apis.Gmail.v1 must be installed. See also quickstart for .NET developers.
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
var req = service.Users.GetProfile("me");
req.Fields = "historyId";
var res = req.Execute();
Console.WriteLine("HistoryId: " + res.HistoryId);
This answer is related to the Java Gmail API Client Library using a service account.
I found that the gmail.users.getprofile() will not work as the object that it returns is of type Class Gmail.Users.GetProfile which does not have an interface to getting a historyId.
com.google.api.services.gmail.model.Profile actually has a getHistoryId() function, but calling service.users().getProfile() will return a Class Gmail.Users.GetProfileobject instead.
To get around this, I use the history.list() function which will always return the latest historyId as part of its response.
Gmail service = createGmailService(userId); //Authenticate
BigInteger startHistoryId = BigInteger.valueOf(historyId);
ListHistoryResponse response = service.users().history().list("me")
.setStartHistoryId(startHistoryId).setMaxResults(Long.valueOf(1)).execute();
I set the max number of results to be 1 to limit the unnecessary data that I get returned back and I will receive a payload that looks like:
{"history":[{"id":"XXX","messages":[{"id":"XXX","threadId":"XXX"}]}],"historyId":"123456","nextPageToken":"XXX"}
The historyId (123456) will be the current historyId of the user. You can grab that historyId using response.getHistoryId()
You can also see that the latest historyId is given in the response if you use the API tester for Users.history: list
https://developers.google.com/gmail/api/v1/reference/users/history/list

paypal pay now and returned variables

I am making a paypal pay now button for my website to add credits that can be used.
I understand the whole buy now and ipn thing but I what I would like to do is that when the user finishes his pay, there should be a way for the IPN to get the username so that I could add the credits into the database.
Is there a way to have the username sent together with the transaction so that it is returned, too? Thank you.
Please do not rely on the notify url.
You can send a 'custom' parameter in your dictionary object to paypal as listed in the Paypal IPN Docs.
paypal_dict = {
"business": "yourpaypalemail#example.com",
"amount": "10000000.00",
"item_name": "name of the item",
"invoice": "unique-invoice-id",
"notify_url": "http://www.example.com/your-ipn-location/",
"return_url": "http://www.example.com/your-return-location/",
"cancel_return": "http://www.example.com/your-cancel-location/",
"custom": request.user.username, #or you can use request.user.pk
}
The 'custom' value will be saved on paypal's server with the transaction and in your IPN object. This is a much better option than having payments with no customer identified.
In the button params, set the notify_url variable to an URL of maximum 255 characters.
PayPal will HTTP POST to this URL with the IPN details (payment_status, payment_date, etc.).
When creating the button, add params to this URL, such as http://yourwebsite.com?username_for_credits=john%20doe
.
When PayPal will make the IPN HTTP POST, you will get back the username you want.

Resources