Validate Google Payment Request API - payment-request-api

I am trying to integrate the payment request api, but I am missing something here..
How to validate payments that were made using the api?
When the user pays my callback is executed, but how do I know the payment is complete?
Here is my code.
paymentRequest.show()
.then((paymentResponse) => {
fetch('http://validate-payment/api')
.then((response) => {
return response.json();
})
.then((json) => {
return paymentResponse.complete('fail'); // Hardcode fail
})
.catch((error) => {
reject();
})
})
.catch((error) =>{
console.log(error.message)
});

When you receive paymentResponse object, this doesn't mean the payment is done. You must post the information to a payment gateway like you do now to process the payment.
Obtain the payment detail with paymentResponse.details and POST it to a payment gateway (in your code it could be "validate-payment/api").
The response from the payment gateway will indicate if the payment was successful or not.
Mind PCI compliance when you work with this API (especially if you handle raw credit card information). Stripe for example does this on behalf of you but not a lot of payment gateways do similar just yet.
paymentRequest.show()
.then((paymentResponse) => {
var details = paymentResponse.details;
fetch('https://validate-payment/api', {
method: 'POST',
body: JSON.stringify(details)
})...

Related

PayPal Checkout UNPROCESSABLE_ENTITY: COMPLIANCE_VIOLATION

I'm trying to integrate PayPal checkout in my angular website. the integration seems to be fine but I always have an error when creating an order. Below you will find all the code I used.
index.html
<head>
...
<script src="https://www.paypal.com/sdk/js?client-id=MY-APP-SANDBOX-ID"></script>
</head>
donation.component.ts
declare var paypal;
...
export class DonationComponent implements OnInit{
...
ngOnInit(): void {
...
paypal.Buttons({
createOrder: (data, actions) => {
return actions.order.create({
purchase_units: [{
description: "Donation For Al-Darb Platform.",
amount: {
currency_code: 'USD',
value: this.value
}
}]
});
},
onApprove: async (data, actions) => {
const order = await actions.order.capture();
console.log(order);
},
onError: err => {
console.log(err);
}
}).render(this.paypalElement.nativeElement);
}
}
donation.component.html
...
<div #paypal></div>
After executing everything works fine only on checkout (after log in to Paypal and validating the payment). I always got the following error HTTP 400:
{
ack: "contingency",
contingency: "UNPROCESSABLE_ENTITY"
data: {name: "UNPROCESSABLE_ENTITY", details: [{ issue: "COMPLIANCE_VIOLATION" ...}],
...
}
COMPLIANCE_VIOLATION
There should be more information like a debug_id you can share, but since it's Algeria I'm sure the issue is the account needing an auto-sweep method set up in order to receive payments.
You can read the PayPal Receive Funds and Automatic Transfer Agreement for Algeria (country code dz) here (other applicable countries on its list have their own URL but agreement text is likely the same)
As detailed there, possible auto-sweep methods include an international bank account, or a local Visa card that is able to withdraw funds (not all cards can do so).
Once you have this set up on the account, you'll be able to receive payments. If it's a live account, contact PayPal's support for any further assistance, as it's not a technical issue for Stack Overflow.
If this were a sandbox mode account: simply create a sandbox business account for a different country such as US to use when testing your integration.

How to activate a PayPal subscription?

I've implemented a recurring payments system using PayPal and the SmartButtons. The customer is able to create the subscription through my system, at the end of the checkout I get the subscription created:
{
"orderID": "3JR7411152833961C",
"subscriptionID": "I-J8CHJ9UKB8JU",
"facilitatorAccessToken": "A21AAElq71jrRrKHzaxxOeA4o7cOie83F_N-LKMZoAe2mhmaANy-a784yj9DUbSlQPIxtu_O-7XyzHWab23gKVgwhqK9Hjaow"
}
in order to activate the subscription and get the payment I need to execute it, so I wrote this method:
let executeAgreement = (paymentToken) => {
paypal.billingAgreement.execute(paymentToken, {}, function (error, billingAgreement) {
if (error) {
console.log(error);
throw error;
}
else {
console.log('Billing Agreement Execute Response');
console.log(JSON.stringify(billingAgreement));
}
});
}
the problem's that I got:
response: {
name: 'BUSINESS_VALIDATION_ERROR',
debug_id: '82426af46aee4',
message: 'Validation Error.',
information_link: 'https://developer.paypal.com/docs/api/payments.billing-agreements#errors',
details: [ [Object] ],
httpStatusCode: 400
},
httpStatusCode: 400
}
I send to executeAgreement the subscriptionId, but I guess the problem it's just that, in the created subscription I only reiceve the id of the subscription not the paymentToken, how can I fix?
Essentially: how can I execute/activate the subscription if I've only the subscription id returned by the following method:
opts.createSubscription = function (data, actions) {
that.step = that.steps.PAYPAL_EXTERNAL_WINDOW;
return actions.subscription.create({
plan_id: that.paymentData.plan.id,
application_context: {
user_action: "CONTINUE",
shipping_preference: 'NO_SHIPPING'
}
});
}
the method above return orderId - subscriptionId - facilitatorAccessToken, seems I'm not able to activate the subscription id after the user as approved the recurring payment through the smart payment buttons.
Actually, I-J8CHJ9UKB8JU is already a created and active subscription and you don't need to execute anything.
The notion of executing a billing agreement is something from old documentation that predates the Subscriptions API.
In the current Sbscriptions API, you would simply create and activate a subscription:
https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_create
Followed by either a redirection to an approval URL, or use of the Smart Payment Button (which is much better, since it opens up an "in context" approval -- no need for any redirect)
So anyway, you have your active Subscription ID: I-J8CHJ9UKB8JU
Now just save this object and associate it with your customer object.

Returning customer information from Paypal Client Side REST Integration Button

I am using the "Client Side REST Integration" using checkout.js (https://developer.paypal.com/docs/integration/direct/express-checkout/integration-jsv4/client-side-REST-integration/)
Is there a way to return the client's information (name + email address) once authorized and the paypal window closes?
Somewhere in the following perhaps?
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!');
});
Thanks
Answered for myself:
actions.payment.execute().then() returns a payment object with this info
onAuthorize: function(data, actions) {
return actions.payment.execute().then(function(payment) {
console.log(payment.payer.payer_info);
});
}

paypal checkout.js check error transaction

I'm working with the checkOut button (https://developer.paypal.com/demo/checkout/#/pattern/confirm) and I'm having some trubles.
I have a question about the process of checking if a credit card is valid or if the account has enough founds for the payment. Take this code for an example:
return actions.payment.execute().then(function(data) {
console.log(data);
});
The question is that if I could know if 'data' has the information about the execution of the payment. If not, where I can find the information?
If that then function is called, then the payment was successful.
return actions.payment.execute().then(function(data) {
console.log('payment was successful!');
}).catch(function(err) {
console.log('payment failed!');
});

Error 500 when calling payment creation via REST API

I trying the new Paypal REST API and want integrate it in sandbox mode into a simple site just to see is it possible to implement one of the following payment flows:
Flow1
1) user fills the payment form, including credit card information
2) user clicks Buy
3) browser stores credit card information in paypal vault via REST API for credit cards (card id used later).
4) browser creates payment for the purchase via REST API call.
5) browser calls app server to ensure that purchase is going on.
5) browser redirects user to url provided by paypal.
6) when user consent/approval received at paypal website, and site redirected back to welcome page,
7) under the hood the IPN callback receives the conformation of payment and marks purchase as paid
8) user obtains access to the service app provides
Flow 2
1) user fills the payment form, including credit card information
2) user clicks Buy
4) browser creates payment for the purchase via REST API call.
5) browser calls app server to ensure that purchase is going on.
5) browser redirects user to url provided by paypal.
6) when user consent/approval received at paypal website, and site redirected back to welcome page,
7) under the hood the IPN callback receives the conformation of payment and marks purchase as paid and uses a bit more pf purchase details like credit card type and last 4 digits to add this info to my purchase object.
8) user obtains the access to services the application provides
8) user obtains access to the service app provides
Reasons to implement all this in such way
Mostly I going this path because i don't want deal with all this PCI compliance, and hones;ty i don't care where customers of my app live, which exactly card numbers they used, or when the card expire, since i don't want use automated subscription like payment, i want use different model:
user gets some pats of service for free, but to use rest of service, user buys time intervals of improved access (e. g. X months or 1 year).
This is what i trying to implement without storing credit cards information or storing as less as possible (paypal credit card id is enough i guess).
Question
Can i implement all this with Paypal REST API?
What i trying to do:
PaypalAdapter.prototype.sendCreditCardPayment = function (amount, description, creditCard, success, failure) {
var ccNumberResult = this.impl.validator.validateCardNumber(creditCard.number);
if (!ccNumberResult.success) {
return this.impl.$q.reject(ccNumberResult);
}
var cardInfo = {
number: ccNumberResult.number,
type: ccNumberResult.type,
expire_month: creditCard.expireMonth,
expire_year: String(creditCard.expireYear),
cvv2: creditCard.securityCode,
first_name: creditCard.firstName,
last_name: creditCard.lastName
};
var self = this;
var defer = self.impl.$q.defer();
this.impl.storeCardAPI(cardInfo,
function cardTokenCreated(cardTokenReply) {
var paymentSettings = {
intent: self.PaymentIntents.Sale,
redirect_urls: {
return_url: self.urls.returnUrl,
cancel_url: self.urls.cancelUrl
},
payer: {
payment_method: self.PayMethods.CreditCard,
funding_instruments: [
{
credit_card_token: {
credit_card_id: cardTokenReply.id
}
}
]
},
transactions: [
{
amount: {
total: String(amount.toFixed(2)),
currency: self.currencyCode
},
description: description
}
]
};
self.impl.createPaymentAPI(paymentSettings, function paymentCreated(payment) {
defer.resolve(payment);
}, function failedToCreatePayment(pcErr) {
defer.reject(pcErr);
});
},
function failedToStoreCard(ctErr) {
defer.reject(ctErr);
});
return defer.promise.then(success, failure);
};
To keep context more clean, here some more pieces of code:
var defaultHeaders = {
Authorization: 'Bearer ' + securityContext.tokens.paypal.access_token,
Accept: 'application/json'
};
var createPaymentResource = $resource(securityContext.configuration.paypal.endPoint + 'payments/payment', {}, {
sendPayment : {
method:'POST',
headers: defaultHeaders
}
});
var saveCreditCardResource = $resource(securityContext.configuration.paypal.endPoint + "vault/credit-cards", {}, {
storeCreditCard: {
method: 'POST',
headers: defaultHeaders
}
});
function storeCardFunc(cardInfo, success, failure) {
return saveCreditCardResource.storeCreditCard(null, cardInfo, success, failure);
}
function createPaymentFunc(paymentInformation, success, failure) {
return createPaymentResource.sendPayment(null, paymentInformation, success, failure);
}
var adapter = new PaypalAdapter($q, securityContext, creditCardValidator, storeCardFunc, createPaymentFunc);
return adapter;
Current "Results"
What i getting:
1) I can store credit card into vault via REST API.
2) i getting error 500 on try to create payment whether i use plain credit card properties to fill credit card funding instrument or try to use credit card token instead.
What i'm doing wrong?
Update
My mistake is a sort of logical with a lack of knowledge.
1) The direct credit cards payments (weather user approves them manually (with intent 'order' and payment_method = 'credit_card'), or not ('sale' intent and payment method 'credit_card') are not available for my country (Republic of Georgia). This is a single reason for the error i see.
Discovered this via Paypal account pages at developer.paypal.com website... It is a frustrating thing. Especially with all this too cryptic "internal server error". I t would be VERY helpful if Paypal would provide at least an informative message "Requested feature not available for your account" with info link to that page with available/enabled features.
Also documentation s a bit broken - some fields like first_name or last_name of payer object of order/payment request are NOT expected by the /payments/payment endpoint...