I do a full refund and get this error message.
RefundRequest refund = new RefundRequest();
Sale sale = new Sale();
sale.setId(paymentId);
try {
sale.refund(context, refund);
} catch (PayPalRESTException e) {
throw new PaymentException(e);
}
response-code: 500 details: name: INTERNAL_SERVICE_ERROR message: An internal service error occurred. details: null debug-id: ddc5e8373a92c information-link: https://developer.paypal.com/webapps/developer/docs/api/#INTERNAL_SERVICE_ERROR
It looks like you are trying to refund the payment using PAY ID ( PAY-XXXX ). You will need to use resulted transaction id for processing the refund.
Please run the refund by passing the transaction id like below:
https://api.sandbox.paypal.com/v1/payments/sale/4JXXXXXXXXXXX2H/refund
Related
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.
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...
I'm using the Paypal rest api and the sdk to build my shopping cart, after a payment is created (POST /v1/payments/payment) and executed (POST /v1/payments/payment/{paymentId}/execute), I'm trying to decode the returned Payment object to retrieve the transaction ID.
I've var_dump the return object and get sth like (just the partial return here..):
object(PayPal\Api\Payment)#137 (1) { ["_propMap":"PayPal\Common\PPModel":private]=> array(8) { ["id"]=> string(28) "PAY-2xxxxxxxxxxxxxxx" .... ["transactions"]=> array(1) ...["related_resources"]=> array(1)
transaction and related resources exist and when I try to get the object value inside:
$result = $payment->execute($paymentExecute, getApiContext());
echo $result->getTransactions()->getRelatedResources()->getSale()->getId();
It said:
Fatal error: Call to a member function getRelatedResources() on a non-object
Is that sth wrong with my syntax..? the transaction ID exist according to var_dump recoard...
You can use something like this:
$transactions = $payment->getTransactions();
$resources = $transactions[0]->getRelatedResources();
$sale = $resources[0]->getSale();
$saleID = $sale->getId();
related_resources in an array, not an object, so there's your problem.
I can't work out why I'm getting this error from Stripe on submission of my form:
An unexpected error has occurred submitting your credit card to our secure credit card processor. This may be due to network connectivity issues, so you should try again (you won't be charged twice). If this problem persists, please let us know!
However the transaction is processed successfully.
My code deviates from the example forms only because I'm validating the code using Parsely and want to generate the token only if the rest of the form is valid:
if $(".error-block").length > 0 && $(".error-block").html() != ''
$.scrollTo($(".error-block"))
Stripe.setPublishableKey($('#stripe_key').val())
stripeResponseHandler = (status, response) ->
if response.error
$(".error-block").text(response.error.message)
$('#join-button').attr("disabled", false).removeClass('disable').html('Join')
else
$form = $('#user_new')
token = response['id']
$('#user_stripe_token').val(token)
$('#user_card_number').val('')
$('#user_card_cvc').val('')
$('#user_card_expiry_month').val('')
$('#user_card_expiry_year').val('')
$form.get(0).submit()
$('#user_new').submit ->
valid = $(#).parsley().isValid()
if valid != false
$('#join-button').attr("disabled", true).addClass('disable').html('Please wait...')
Stripe.card.createToken({
number: $('#user_card_number').val(),
cvc: $('#user_card_cvc').val(),
exp_month: $('#user_card_expiry_month').val(),
exp_year: $('#user_card_expiry_year').val()
name: $('#user_first_name').val() + " " + $('#user_last_name').val()
}, stripeResponseHandler)
return false
return false
Any ideas where I'm going wrong?
I need to refund payment to a customer on behalf of a third party. I have studied permission APIs how to get access token and verification code to use it in authentication API to generate signature and timestamp. But after this i am still confused as to how to use this in Refund API. Currently this is my refund paypal code
CallerServices caller = new CallerServices();
APIProfile profile = ProfileFactory.createSignatureAPIProfile();
if(Configuration.getProperty("PaypalEnvironment").equals("sandbox"))
{
profile.setAPIUsername(Configuration.getProperty("PaypalAPIUsername"));
profile.setAPIPassword(Configuration.getProperty("PaypalAPIPassword"));
profile.setSignature(Configuration.getProperty("PaypalSignature"));
profile.setEnvironment(Configuration.getProperty("PaypalEnvironment"));
caller.setAPIProfile(profile);
}
RefundTransactionRequestType pprequest = new RefundTransactionRequestType();
if ((amount != null && amount.length() > 0)
&& (refundType.equals("Partial"))) {
BasicAmountType amtType = new BasicAmountType();
amtType.set_value(amount);
amtType.setCurrencyID(CurrencyCodeType.fromString(currencyCode));
pprequest.setAmount(amtType);
}
pprequest.setVersion("63.0");
pprequest.setTransactionID(transactionId);
pprequest.setMemo(note);
pprequest.setRefundType(RefundType.fromString(refundType));
RefundTransactionResponseType ppresponse = (RefundTransactionResponseType) caller
.call("RefundTransaction", pprequest);
In this code how do i embed the signature?
For refund it is simple. Once you get the request token and verification code that's it. You don't need to pass this to refund API. All you have to above is just add this line
profile.setSubject(emailid);
and it then it gets refunded.