I am making a website in which users of a website can pay each other on-site like a fiver, Upwork and other platforms.
I want to use the PayPal payment gateway for this purpose. And using Django-rest-framework at the backend.
Are there any tutorials or documentation you guys can refer me to?
here is code when I try to send request to Paypal using payee method.
class PaymentP2P(APIView):
permission_classes = ()
# authentication_classes = (SessionAuthentication, TokenAuthentication)
def post(self,request):
email_request=request.data['payee']
price_to_pay = str(request.data['price'])
payment = paypalrestsdk.Payment(self.build_request_body(email_request,price_to_pay))
print(payment)
if payment.create():
print("Payment created successfully")
else:
print(payment.error)
return Response({'paymentID':payment.id},status=200)
#staticmethod
def build_request_body(email_user="payee#email.com",price="220.00"):
"""Method to create body with a custom PAYEE (receiver)"""
return \
{
"intent": "AUTHORIZE",
"purchase_units": [
{
"amount": {
"total": price,
"currency": "USD"
},
"payee": {
"email_address": "sb-loe4o1374588#personal.example.com"
},
},
]
}
For one user to pay another user's email, you can use PayPal Checkout with a payee variable: https://developer.paypal.com/docs/checkout/integration-features/custom-payee/
Here are some front-end demo patterns of the basic checkout:
One that calls endpoints on your server to set up and capture
transactions:
https://developer.paypal.com/demo/checkout/#/pattern/server
One that
does not do that, and only uses client-side js:
https://developer.paypal.com/demo/checkout/#/pattern/client
I created PayPal Sandbox Business Account with EUR, USD and PLN enabled.
I created Sandbox REST API linked to account above.
I linked my Paypal Account in Braintree Sandbox ( https://sandbox.braintreegateway.com/ ) in Account -> My User.
I typed in REST API keys in Settings -> Processing -> PayPal.
I made sure my default merechant is PLN currency.
I created backend methods for ClientToken and ProcessingNounce using Braintree .NET docs.
I prepared frontend using dropin from Braintree docs.
Code:
braintree.dropin.create({
authorization: result.token,
container: '#dropin-braintree-container',
paypal: {
flow: 'checkout',
amount: '#Model.TransactionDetails.CalculatedTotalPrice',
currency: 'PLN'
}, function (createErr, instance) { ... /* button listener and processing stuff here */ ... });
The code above works fine! I can finish transaction with Paypal client EUR account, Paypal client PLN, Braintree credit card etc.
Client told me that he don't want to recive payment in PLN currency, but in EUR, and there I am having a trouble.
I changed line:
currency: 'EUR'
And also I changed default merechant in Braintree to EUR (without changing merechant I was getting "The currency of this PayPal transaction must match the currency of the merchant account (2091)")
Now when I try to pay with any PayPal account and any option within I am getting "The customer's bank is unwilling to accept the transaction. For credit/debit card transactions, the customer will need to contact their bank for more details regarding this generic decline; if this is a PayPal transaction, the customer will need to contact PayPal. (Declined: 2046)". I can finish transaction only using braintree sample cards.
There is no way to debug this, API Calls in PayPal are telling me something is wrong, but I can't click and view details:
When I switch back to PLN in frontend code and to default PLN merechant in Braintree, transaction works fine again.
I need help with that, it's not possible to debug it. Idk if I am missing some params specific for EUR currency or if its PayPal bug.
Thanks for help in advance!
EDIT: I have digged deeper, I checked POST request in Chrome dev tools on Sandbox Api Calls page to get details:
{
"create_time":"30 Jan 2019 05:07:53",
"correlation_id":"304384c194ece",
"resource_id":"PAY-6JB373950C8856440LRI2DGI",
"api_response":{
"additional_properties":"xxxxxx",
"body":{
"debug_id":"304384c194ece",
"details":"xxxxxx",
"information_link":"https://developer.paypal.com/docs/api/payments/#errors",
"message":"The request was refused",
"name":"TRANSACTION_REFUSED"
},
"duration_time":"xxxxxx",
"header":{
"APPLICATION_ID":"xxxxxx",
"CALLER_ACCT_NUM":"LG4QN5BPXPW7N",
"Content-Language":"*",
"Date":"Wed, 30 Jan 2019 13:07:57 GMT",
"paypal-debug-id":"304384c194ece"
},
"status":400
},
"client_id":"ASKLWoEWn6q9ZNqkzpj7pulX4x0h9iD-Fy6_yzyfKaiNlHz7VMVwgPlk6Hpaq5-pG3_pcA84qIzOEx9q",
"api_request":{
"additional_properties":"xxxxxx",
"body":{
"payer_id":"CCD9AZVEJK8UN",
"transactions":[
{
"amount":{
"currency":"EUR",
"total":"22.00"
},
"payment_options":{
"allowed_payment_method":"IMMEDIATE_PAY"
}
}
]
},
"header":{
"accept":"application/json",
"accept-encoding":"gzip, deflate",
"authorization":"xxxxxx",
"client-auth":"No cert",
"content-length":"152",
"content-type":"application/json",
"host":"api.sandbox.paypal.com",
"paypal-client-metadata-id":"EC-6DS628633U9315453",
"paypal-request-id":"1548853672_qc053cdc",
"pp_remote_addr":"xxxxxx",
"user-agent":"Braintree/1.0",
"x-ads-si-context":"xxxxxx",
"x-newrelic-id":"UAMPU1RWGwEJVlNaAQk=",
"x-newrelic-transaction":"PxQFUVYHXAtTAlhWBwUCUAUHFB8EBw8RVU4aBAoOUgYBXAAFCARRVVMAA0NKQQ8FCFADA1UIFTs=",
"x-pp-ads-performed":"xxxxxx",
"x-pp-ads-request-id":"xxxxxx",
"x-pp-ads-usecase-id":"xxxxxx",
"x-pp-anomaly-detection-mechanism":"xxxxxx",
"x-pp-corrid":"304384c194ece",
"x-pp-idempotencyid":"304384c194ece_1548853673",
"x-pp-silover":"xxxxxx",
"x-pp-slingshot-targetapp":"apiplatformproxyserv",
"x-request-id":"xxxxxx",
"x-slr-orig-script_uri":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-6JB373950C8856440LRI2DGI/execute"
},
"method":"POST"
},
"account_number":"2117554163912301260",
"http_status":400,
"url":"/v1/payments/payment/PAY-6JB373950C8856440LRI2DGI/execute"
}
According to docs this error can be basically anything.
EDIT2:
Sample request of successfull payment in PLN:
{
"create_time":"30 Jan 2019 06:58:59",
"correlation_id":"7cabc2b46e5bb",
"resource_id":"PAY-305699707J366792MLRI3XEA",
"api_response":{
"additional_properties":"xxxxxx",
"body":{
"cart":"29R95576JY4406634",
"create_time":"2019-01-30T14:59:03Z",
"id":"PAY-305699707J366792MLRI3XEA",
"intent":"sale",
"links":[
{
"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-305699707J366792MLRI3XEA",
"method":"GET",
"rel":"self"
}
],
"payer":{
"payer_info":{
"country_code":"DE",
"email":"*****",
"first_name":"*****",
"last_name":"*****",
"payer_id":"CCD9AZVEJK8UN"
},
"payment_method":"paypal",
"status":"VERIFIED"
},
"state":"approved",
"transactions":[
{
"amount":{
"currency":"PLN",
"details":"xxxxxx",
"total":"22.00"
},
"payee":{
"email":"*****",
"merchant_id":"LG4QN5BPXPW7N"
},
"payment_options":{
"allowed_payment_method":"IMMEDIATE_PAY",
"recurring_flag":"xxxxxx",
"skip_fmf":"xxxxxx"
},
"related_resources":[
{
"sale":{
"amount":{
"currency":"PLN",
"details":{
"subtotal":"22.00"
},
"total":"22.00"
},
"create_time":"2019-01-30T14:59:02Z",
"id":"4AK709636U844620F",
"links":[
{
"href":"https://api.sandbox.paypal.com/v1/payments/sale/4AK709636U844620F",
"method":"GET",
"rel":"self"
},
{
"href":"https://api.sandbox.paypal.com/v1/payments/sale/4AK709636U844620F/refund",
"method":"POST",
"rel":"refund"
},
{
"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-305699707J366792MLRI3XEA",
"method":"GET",
"rel":"parent_payment"
}
],
"parent_payment":"PAY-305699707J366792MLRI3XEA",
"payment_mode":"INSTANT_TRANSFER",
"protection_eligibility":"ELIGIBLE",
"protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE",
"state":"completed",
"transaction_fee":{
"currency":"PLN",
"value":"2.21"
},
"update_time":"2019-01-30T14:59:02Z"
}
}
]
}
]
},
"duration_time":"xxxxxx",
"header":{
"APPLICATION_ID":"xxxxxx",
"CALLER_ACCT_NUM":"LG4QN5BPXPW7N",
"Content-Language":"*",
"Date":"Wed, 30 Jan 2019 14:59:03 GMT",
"paypal-debug-id":"7cabc2b46e5bb"
},
"status":200
},
"client_id":"ASKLWoEWn6q9ZNqkzpj7pulX4x0h9iD-Fy6_yzyfKaiNlHz7VMVwgPlk6Hpaq5-pG3_pcA84qIzOEx9q",
"api_request":{
"additional_properties":"xxxxxx",
"body":{
"payer_id":"CCD9AZVEJK8UN",
"transactions":[
{
"amount":{
"currency":"PLN",
"total":"22.00"
},
"payment_options":{
"allowed_payment_method":"IMMEDIATE_PAY"
}
}
]
},
"header":{
"accept":"application/json",
"accept-encoding":"gzip, deflate",
"authorization":"xxxxxx",
"client-auth":"No cert",
"content-length":"152",
"content-type":"application/json",
"host":"api.sandbox.paypal.com",
"paypal-client-metadata-id":"EC-29R95576JY4406634",
"paypal-request-id":"1548860338_ae402q2s",
"pp_remote_addr":"xxxxxx",
"user-agent":"Braintree/1.0",
"x-ads-si-context":"xxxxxx",
"x-newrelic-id":"UAMPU1RWGwEJVlNaAQk=",
"x-newrelic-transaction":"PxRUBAIHCwsDXFJXVQdVB1YAFB8EBw8RVU4aVFxbUFQCVg9WCQdSA11UBUNKQQ8FCFADA1UIFTs=",
"x-pp-ads-performed":"xxxxxx",
"x-pp-ads-request-id":"xxxxxx",
"x-pp-ads-usecase-id":"xxxxxx",
"x-pp-anomaly-detection-mechanism":"xxxxxx",
"x-pp-corrid":"7cabc2b46e5bb",
"x-pp-idempotencyid":"7cabc2b46e5bb_1548860339",
"x-pp-silover":"xxxxxx",
"x-pp-slingshot-targetapp":"apiplatformproxyserv",
"x-request-id":"xxxxxx",
"x-slr-orig-script_uri":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-305699707J366792MLRI3XEA/execute"
},
"method":"POST"
},
"account_number":"2117554163912301260",
"http_status":200,
"url":"/v1/payments/payment/PAY-305699707J366792MLRI3XEA/execute"
}
I repeated:
1. I created PayPal Sandbox Business Account with EUR, USD and PLN enabled.
2. I created Sandbox REST API linked to account above.
4. I typed in REST API keys in Settings -> Processing -> PayPal. (in Braintree sandbox)
And it works now. I double checked, setting are exactly the same as previous. I remeber in the 1 step I added EUR currency later, so it might be some kind of PayPal bug. Or maybe REST API App doesn't update currency settings from account.
EDIT: On phone assistant its working now problem just exist in google action simulator
I just try to setup Google Actions SDK account Linking with implicit grant and try to test it in Simulator.
First question is this even possible in Simulator?
To Do so I added at the action console account linking with the type
implicit grant to my action.
The url I used is working.
Now I added a signup request to my action. For testing so if I write signup in simulator the server response with:
{
conversationToken: JSON.stringify(state),
expectUserResponse: true,
expectedInputs: [
{
inputPrompt: {
initialPrompts: [
{
textToSpeech: "PLACEHOLDER_FOR_SIGN_IN"
}
],
noInputPrompts: []
},
possibleIntents: [
{
"intent": "actions.intent.SIGN_IN",
"inputValueData": {}
}
],
speechBiasingHints: []
}
]
}
After this the server didn't request the sign in page route (the address is correct!). It just responds with SignIN intent ERROR :
{
"isInSandbox'": false,
"surface": {
"capabilities": [
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.SCREEN_OUTPUT"
}
]
},
"inputs": [
{
"rawInputs": [
{
"query": "i think so",
"inputType": "VOICE"
}
],
"arguments": [
{
"name": "SIGN_IN",
'extension': {
"#type": "type.googleapis.com/google.actions.v2.SignInValue",
"status": "Error"
}
}
],
"intent': "actions.intent.SIGN_IN"
}
],
"device": {
"locale": "en-US"
},
"conversation": {
"conversationId": "1494606917128",
"type": "ACTIVE",
"conversationToken": "[\"_actions_on_google_\"]"
}
}
Why? Where is the problem? Can I see a error message somewhere?
Here is what happen in the simulator between 3 and 4:
Is it same when you use the phone app? For me it opens an embedded browser with my /auth endpoint, which the simulator doesn’t do.
I am able to make it WORKING after a long time.
We have to enable the webhook first and we can see how to enable the webhook in the dialog flow fulfillment docs
If we are going to use Google Assistant, then we have to enable the Google Assistant Integration in the integrations first.
Then follow the steps mentioned below for the Account Linking in actions on google:-
Go to google cloud console -> APIsand Services -> Credentials -> OAuth 2.0 client IDs -> Web client -> Note the client ID, client secret from there
-> Download JSON - from json note down the project id, auth_uri, token_uri
-> Authorised Redirect URIs -> White list our app's URL -> in this URL fixed part is https://oauth-redirect.googleusercontent.com/r/ and append the project id in the URL
-> Save the changes
Actions on Google -> Account linking setup
1. Grant type = Authorisation code
2. Client info
1. Fill up client id,client secrtet, auth_uri, token_uri
2. Enter the auth uri as https://www.googleapis.com/auth and token_uri as https://www.googleapis.com/token
3. Save and run
4. It will show an error while running on the google assistant, but dont worry
5. Come back to the account linking section in the assistant settings and enter auth_uri as https://accounts.google.com/o/oauth2/auth
and token_uri as https://accounts.google.com/o/oauth2/token
6. Put the scopes as https://www.googleapis.com/auth/userinfo.profile and https://www.googleapis.com/auth/userinfo.email
and weare good to go.
7. Save the changes.
In the hosting server logs, we can see the access token value and through access token, we can get the details regarding the email address.
Append the access token to this link "https://www.googleapis.com/oauth2/v1/userinfo?access_token=" and we can get the required details in the resulting json page.
accessToken = req.get("originalRequest").get("data").get("user").get("accessToken")
r = requests.get(link)
print("Email Id= " + r.json()["email"])
print("Name= " + r.json()["name"])
P.S. You can use the Grant Type as Implicit also instead of Authorisation code.
So, I am trying to figure this out but cannot seem to get this right.
I am trying to integrate paypal express onto a website. I have the sandbox environment with the facilitator and buyer accounts.
I paste in the sample code and change the client values and transaction details etc... like so:
paypal.Button.render({
env: 'sandbox', // Optional: specify 'sandbox' environment
client: {
sandbox: 'My Client ID here'
},
payment: function () {
var env = this.props.env;
var client = this.props.client;
return paypal.rest.payment.create(env, client, {
intent: "sale",
payer: { payment_method: "paypal" },
transactions: [
{
amount: { total: '14.00', currency: 'GBP' },
description: "This is a payment description"
},
],
redirect_urls: {
return_url: "http://somesite.com/success",
cancel_url: "http://somesite.com/cancel"
}
});
},
commit: true, // Optional: show a 'Pay Now' button in the checkout flow
onAuthorize: function (data, actions) {
// Optional: display a confirmation page here
alert('confirmation here');
return actions.payment.execute().then(function () {
// Show a success page to the buyer
alert('success here');
});
}
}, '#paypal-button');
The issue I am facing is that when you hit the paypal button - in the popup I do not see the amount.
Then when continuing, I get an error from javascript like so:
JavaScript runtime error: Error: Payment Api response error:
{
"name": "INTERNAL_SERVICE_ERROR",
"message": "An internal service error has occurred",
"information_link": "https://developer.paypal.com/docs/api/#INTERNAL_SERVICE_ERROR",
"debug_id": "a9ceebeb96bab"
}
Error: Payment Api response error:
{
"name": "INTERNAL_SERVICE_ERROR",
"message": "An internal service error has occurred",
"information_link": "https://developer.paypal.com/docs/api/#INTERNAL_SERVICE_ERROR",
"debug_id": "a9ceebeb96bab"
}
at Anonymous function (https://www.paypalobjects.com/api/checkout.js:8325:17)
at _loop2 (https://www.paypalobjects.com/api/checkout.js:1509:25)
at SyncPromise.prototype.dispatch (https://www.paypalobjects.com/api/checkout.js:1542:17)
at SyncPromise.prototype.resolve (https://www.paypalobjects.com/api/checkout.js:1480:13)
at Anonymous function (https://www.paypalobjects.com/api/checkout.js:1533:25)
at _loop2 (https://www.paypalobjects.com/api/checkout.js:1509:25)
at SyncPromise.prototype.dispatch (https://www.paypalobjects.com/api/checkout.js:1542:17)
at SyncPromise.prototype.resolve (https://www.paypalobjects.com/api/checkout.js:1480:13)
at Anonymous function (https://www.paypalobjects.com/api/checkout.js:1533:25)
at _loop2 (https://www.paypalobjects.com/api/checkout.js:1509:25)
So how the heck do I know what the error is?
Second question: Hopefully when this is all working with your help, how can I get back the response and determine if its a success or failure of payment along with detailed information to log it on my website and display to the user? What about custom variables like paymentID generated from my site? Can I get that information back?
Thank you
You're missing some important information for the API.
Things like AMOUNT{}, and others.
https://developer.paypal.com/docs/integration/direct/create-process-order/
I have a problem with this as well, I can get to the actions.payment.execute() and I get an error, _loop2 etc etc.