I need integrate paypal subscriptions to my project.
I use new paypal subscriptions api https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions and need to know how i can identify payer and my own db user.
Here is scenario in my mind:
I create my own db user with signup form.
I set my own user id to paypal api call
After user confirm subscription paypal return me subscriptions id, then i call paypal api to get details of returned subscription and see my own db user id
But looks like paypal cant provide it.
here is my smart checkout button code
paypal.Buttons({
style: {
layout: 'horizontal',
size: 'small',
color: 'blue',
label: 'pay',
height: 55,
tagline: 'false'
},
createSubscription: function(data, actions) {
return actions.subscription.create({
'plan_id': 'P-5GS67390M7258253CLUHXAHQ',
'metadata' : {
'user_id' : 'myuserid'
}
});
},
onApprove: function(data, actions) {
console.log(data);
alert('You have successfully created subscription ' + data.subscriptionID);
}
}).render('#paypal-button-container');
</script>
I found only one way how i can do it
User insert all data to signup form and then click on paypal button
After success paypal payment on
onApprove: function(data, actions) {
$('#myform').append('<input name="subscriptions_id" value="data.subscriptionID"')
$('#myform').submit()
alert('You have successfully created subscription ' + data.subscriptionID);
}
What is the best way to add subscriptions id for mysql db user?
The solution in the question is one possible way. The problem with it is that if the client goes down before sending the data to the server, the association between user_id and subscription_id is lost.
The way around it is to send the user_id to paypal as custom_id. That custom_id is then a part of the subscription data, retained on the payapl server, shown in the paypal billing UI for the subscriptiion details. I do not yet know it for sure, but strongly suspect it is also sent to the webhook.
see PayPal API documentation for creating a subscription
So ideally combine both. Have a webhook to associate the custom_id (your user_id) with the subscription. Have the API call (form post) like you do. If either way fails, you have the fallback.
UPDATE 2021-09-02: I myself use that approach in our web billing solution. One thing I noticed, statistically, it is a very rare event that the web client goes down before getting a response back. I know it because webhook calls come from hours to days after the event. After several hundreds of subscriptions that I analyzed, I have seen not a single case where the webhook came to patch up a missing transaction.
I do not know why it is so. It certainly exceeded my expectations.
My guesses are 1. PayPal server replies fast 2. my PWA is written well enough to warn user to wait a bit not close the browser window until the confirmation screen.
Still I recommend to implement webhook. It would be needed for all the other cases where user cancels subscription directly on the paypal, or such other events.
The solution in the question is correct, the subscription-id should be stored and associated with the internal user-id at creation time, which for subscriptions occurs right after approval (in the onApprove function)
The fetch API can be used instead of a form post to communicate this subscription-id to the server, along with the user-id to associate it with -- similar to the examples in https://developer.paypal.com/demo/checkout/#/pattern/server
Related
Afternoon
I am a bit of a PayPal integration newbie and having been working on a project where customers use a subscription button to purchase goods. Everything works well however I need to retrieve subscription data after approval for further use. Initially I need the email address so we can send a customised automated email thanking the customer for their purchase but going forward would like the majority of the data so it can be placed in an SQL database.
The onApprove: function(data, actions) seems to be the place to enter code but not overly sure where to start. The subscriptionID seems to be pulled and used within the default code, but when I try and pull another piece of data nothing happens.
onApprove: function(data, actions) { //alert('You have successfully created subscription ' + data.subscriptionID); alert('Here is the email address ' + data.subscriber.email_address); }
Is my reference to the email address wrong or does paypal only give you access to the subscriptionID which can then be passed to another PHP page and I can use do a REST API request for the subscription data??
Many thanks chris
console.log(data) in the onApprove will show you the data that is available on the client side.
To log information to a server, you should not depend on approval notifications from the client, since they may fail for any number of reasons. Instead, (using the correct clientid) subscribe to webhooks related to subscriptions, particularly the PAYMENT.SALE.COMPLETED event so you receive an update every time a subscription is successfully renewed.
For reconciliation (so you know what payment is for what), you can pass your own arbitrary custom_id when the subscription is first created. This will be returned in the webhook.
I'm trying to implement the new PayPal Orders API, here is what I did:
Create a developer account, add an app name and then I have Client Id and Secret.
Use OrderCreateRequest to create an Order
Get approvel_url from the resposne->result->links
Redirect to this approvel_url and finish the payment
Paypal will redirect back to my website.
But I never got any thing from the PayPal testing account,Please, what did I miss?
Edit:
On No.4, when redirects to the PayPal page, somehow it only shows 'Continue' button on the page, not the 'make payment' button.
You are missing:
Display an order review page to the payer.
Capture the order with an API call, which (if successful) will return the transaction ID in the purchase_units[0].payments.captures[0] object.
On success, display a thank you/confirmation page.
Without the final capture API call, there is no PayPal transaction.
You are also still using an old integration method based on redirects, which is for old websites. Current PayPal Checkout integrations use no redirects. At all.
Instead of redirecting, make two routes on your server, one for 'Create Order' and one for 'Capture Order', documented here. These routes should return only JSON data (no HTML or text). When a capture response is successful, store its resulting payment details in your database (particularly purchase_units[0].payments.captures[0].id, the PayPal transaction ID) and perform any necessary business logic (such as sending confirmation emails or reserving product) right before sending your return JSON.
Pair those two routes with the following approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
createSubscription: function(data, actions) {
console.log($('#donation-details').val());
return actions.subscription.create({
'plan_id': window.VUE_DONATION_MODULE.getPlanId(),
// I want to add meta data about the subscription
'description': $('#donation-details').val(),
'application_context':{brand_name:$('#donation-details').val()}
});
},
onApprove: function(data, actions) {
$('#step-7').removeClass('active').fadeOut();
$('#step-9').addClass('active').fadeIn();
}
I am using PayPal Smart Buttons to make a subscription, and want to add metadata. For a one-time payments I used the 'description' field to enter this metadata. Please help me find a way to record metadata for subscriptions; I want it to display it under transaction details after loging into PayPal, in both merchant account and customer account.
Plans have a description field you can use at original plan creation time: https://developer.paypal.com/docs/api/subscriptions/v1/#plans-create-request-body
If you need per-user metadata to be part of the plan description, you must create a new plan per user.
If you just need to associate additional metadata with a user's subscription, you must do this in your own database. Associate the subscription ID object with the user the moment it is created by your site/application, and so all additional metadata can be stored by your site/application, and be looked up by either the user or the subscription ID.
I am trying to set up a recurring payment with PayPal Subscription REST API. I'm following the Basic Integration in PayPal Developer Portal, using as suggested the Smart Payment Button. Besides, I'm using a WebHook to "capture" events related to subscription.
As the tutoria suggest, I created a Product and a Plan.
Now, I rendered the Smart Payment Button in a page (using the example), and when clicked it triggers the PayPal authorization flow. When the user complete the subscription process, the BILLING.SUBSCRIPTION.CREATED event is triggered. Later, also the PAYMENT.SALE.COMPLETED and BILLING.SUBSCRIPTION.ACTIVATED are triggered, and I receive data in my WebHook. Now, I have troubles in identifying which user activated the subscription. My idea is to pass a custom variable (with something allows me to identify the user) and retrive it later when the WebHook post me data, but I can't undertand how to do it. Anyway, is this the best way to do it? Or there is another solution?
I solved this using "custom_id" in the smart button:
return actions.subscription.create({
'plan_id': 'PLAN_ID',
'custom_id': 'CUSTOM_ID'
});
Then, I receive custom_id from webhooks or querying the subscription.
I was looking the PayPal interactive integration demo link.
At some point after the user complete the payment flow, the client reach the code:
// onAuthorize() is called when the buyer approves the payment
onAuthorize: function(data, actions) {
// Make a call to the REST api to execute the payment
return actions.payment.execute().then(function() {
window.alert('Payment Complete!');
});
}
In a real scenario, instead of an alert, I would probably like to send the server a instruction to ship a product or update the user plan. And it would probably be done via an HTTP POST request.
How can the server know that indeed a payment was made and it was not a result of an hacker sending an http post request manually?
After actions.payment.execute() you can call your server and have it make a GET call to verify the payment has been completed: https://developer.paypal.com/docs/integration/direct/express-checkout/integration-jsv4/advanced-payments-api/show-payment-details/
Your idea is correct, the server cannot know if the payment was really made. This client API is intended for things like donations, where no request to any servers is necessary. The client callback can then be used to display a "thank you" note or similar to the user.
For most cases (like online shops etc.) you will want to use the server API. That way, the PayPal server will send a request to your server, so you can validate that it really is a genuine payment confirmation.
1) generate a unique reference server side in your database that includes the payment details. For example:
My paypal references table
| Amount: $1.00 | Reference: ECHI5786786 |
2) Pass the payment reference in your transaction object before excuting the payment.
"transactions": [
{
"amount": {
"total": "1.99",
"currency": "USD"
},
"soft_descriptor": "ECHI5786786" //this is your unique reference
]
3) In your PayPal app configuration, on the developers site, set a webhook to your server for "payment sale completed". PayPal will call your url with the transaction details including the unique reference. Record the details in your database. For example
My paypal confirmed completed payments table
| Amount paid: $1.00 | Reference: ECHI5786786 |
4) When PayPal confirms the payment is complete client side, send a request to your server to confirm payment details
// Make a call to the REST api to execute the payment
return actions.payment.execute().then(function() {
//ajax to your server here with "soft_descriptor"
//if ajax success, then all good
});
Serverside confirmation
Confirm that the reference is in both tables and that the amount matches