I'm trying to test refunds in the Paypal Sandbox, but I'm getting a confusing response; The transaction id is not valid.
I've managed to confirm the following:
I'm passing in the transaction ID that I get from the PAYMENTREQUEST_n_TRANSACTIONID of GetExpressCheckoutDetails.
The Transaction ID is not being modified in between getting it from GetExpressCheckoutDetails and passing it in RefundTransaction.
This happens regardless of whether or not I pass INVOICEID.
The PAYMENTACTION of DoExpressCheckoutPayment for this was Sale.
Am I making any obviously incorrect assumptions here? Does it have anything to do with this being a Sandbox order (Doubtful)? Am I getting the Transaction ID from the wrong source?
Just in case any details are needed, I'll leave the full response...
{
"TIMESTAMP": "2014-01-06T18:15:35Z",
"CORRELATIONID": "cb90afac455c",
"ACK": "Failure",
"VERSION": "109",
"BUILD": "9138168",
"L_ERRORCODE0": "10004",
"L_SHORTMESSAGE0": "Transaction refused because of an invalid argument. See
additional error messages for details.",
"L_LONGMESSAGE0": "The transaction id is not valid",
"L_SEVERITYCODE0": "Error",
"REFUNDSTATUS": "None",
"PENDINGREASON": "None"
}
And the fields/values of the RefundTransaction call itself... (Redacting credentials even though it's sandbox)
{
"METHOD": "RefundTransaction",
"TRANSACTIONID": "30888131YM063371A",
"USER": "[redacted]",
"REFUNDTYPE": "Partial",
"CURRENCYCODE": "USD",
"REFUNDSOURCE": "any",
"AMT": 57.21,
"PWD": "[redacted]",
"SIGNATURE": "[redacted]",
"VERSION": 109
}
EDIT: (May post as an answer if Robert doesn't update his answer after a while, since he deserves credit for this)
PayPal_Robert noted that in my SetExpressCheckout call, I was setting the recipient to the actual account that payments would be going to with the live API when - since this is Sandbox - I should have been sending it to the -facilitator account.
I can't find any transactions with that transactionID in the sandbox environment - across all accounts either. I suspect it's getting mangled somewhere.
The only thing I found for the same API caller is an order with transactionID O-072365850X147461B, created on the 2nd of January.
Can you re-create the entire flow, including creating a fresh transaction and try with that?
If you still run into issues, please file a ticket with us at https://paypal.com/mts (24x7) or shoot me an email (address in profile, I only work GMT however.)
Related
I'm trying to perform a super-simple call to the PayPal Payments API.
{
"intent":"sale",
"payer": {
"payment_method":"credit_card",
"funding_instruments": {
"credit_card_token": {
"credit_card_id":"CARD-XXXXXXXXXXXXXXXXXXXXXXXX"
}
}
}
}
I've tried adding/removing various parts of the request, and I've had minimal success, but inevitably, I come across an error of "Incoming JSON request does not map to API request MALFORMED_REQUEST".
According to the documentation, these are the only required parameters, but I've tried different funding_instruments, adding payer_info, adding transactions, using credit_card_token and credit_card... nothing seems to work, and the documentation is useless for troubleshooting.
Is there a way to be able to determine WHY this is a malformed request? Most of the documentation I am coming across uses payment_method: paypal instead of credit_card. What are better ways for me to troubleshoot why this request is failing?
There are a few things to consider first. Are you in the US?
if not you will need to consider if your country can use the API. You can find Information of which countries can use the API here https://developer.paypal.com/docs/integration/direct/rest/country-codes/
You might also need to validate your json. I've tested what you have posted here, but you might not be generating the information properly in your app. check the output and make sure that it is valid json--MALFORMED_REQUEST is an indicator that required key/value pairs are missing or that the json is not valid... this website will help you validate the json output https://jsonlint.com/
check your headers carefully to ensure that you have a properly formatted header request header. you can check your headers against the api requirements here https://developer.paypal.com/docs/api/overview/#http-request-headers
paypal notes that they provide an error code as a json string for errors arising in this manner, and that details may or may not be provided in the response. error response codes are in the 400 and 500 ranges and correspond to error messages (these are listed on the headers page given above)
However, given your error message which is not listed i'm going to guess that you are missing required key/value pairs in your json...
paypal says that INTENT AND PAYER OBJECTS ARE REQUIRED, but the example payment that they give lists a great deal of information that your sample json is missing--
among those items are the transaction details which are required...
per paypal's api docs "Include payer, transaction details...
paypal api documentation gives examples of of the required payer and intent objects here https://developer.paypal.com/docs/api/payments/
restrictions are further placed on direct credit card payments: they may only be accepted from the UK or US, and only if the account is payment pro enabled...
options for avoiding this issue are:
1) paypal classic api direct payments--https://developer.paypal.com/docs/classic/paypal-payments-pro/integration-guide/direct-payment/
2) braintree direct: https://www.braintreepayments.com/products/braintree-direct
3) or payflow pro: https://developer.paypal.com/docs/classic/products/payflow
Funding instruments in an array so the request should be something like below.
Transaction is required as that's the only way you will be able to specify what amount you are capturing.
{
"intent":"sale",
"payer": {
"payment_method":"credit_card",
"funding_instruments": [ {
"credit_card_token": {
"credit_card_id":"CARD-27V22453CF057824JLLDIA7Q"
} }
]
},
"transactions": [
{
"amount": {
"total": "30.11",
"currency": "GBP",
"details": {
"subtotal": "30",
"tax": "0.07",
"shipping": "0.03",
"handling_fee": "1.00",
"shipping_discount": "-1.00",
"insurance": "0.01"
}
}
}]
}
I'm painfully trying to get going with PayPal's IPN system. Via the Sandbox, I've got it processind payments and sending notifications to my IPN listener.
Question: what in the response denotes that the payment was succesful? verify_sign looks promising, but then payer_status says unverified, which is less so. What would this look like if paymeny had failed?
Example response on success (truncated for brevity):
{
"txn_type": "subscr_signup",
"subscr_id": "I-X5CCUV52M245",
"option_selection1": "Some Product",
"residence_country": "GB",
"mc_currency": "GBP",
"item_name": "My Project",
"recurring": "1",
"verify_sign": "AxQ2151HawsltpX50Ic0ERjMvTm2AKxR9ZhaRWhY2vsawH.ST73m1oWR",
"payer_status": "unverified",
"test_ipn": "1",
"payer_email": "xxx#xxx.xxx",
"payer_id": "88F6NGLATYQ3S",
"option_name1": "Subscription options",
"reattempt": "1",
"item_number": "1",
"subscr_date": "11:23:05 May 24, 2016 PDT",
"period1": "2 D",
"mc_amount1": "0.00",
"period3": "1 Y",
"mc_amount3": "10.00",
"ipn_track_id": "1d86661393869"
}
I'm unsure how to mimick a failed payment (e.g. legitimate card details but not enough funds in the account) via the Sandbox (since it's all pretend day) so I don't have anything to compare to.
This is not a payment. It is a signup. All you should do when receiving this message is register the user. You will get another transaction for the payment. Until you do, don't give the new user the permissions concerned, or the product, or whatever it is you're selling.
Note that you can get the payment before or after the signup.
I'm developing a marketplace-like application that has support for payment processing through Braintree. However, most of my transactions will be quite small, and given the rate that Braintree charges, it's not feasible for me to process the transaction every time a user makes a purchase.
Therefore, I want to aggregate the payments on the backend, and charge users once they reach $X in accumulated expenditures, or once Y days have passed.
Is this method possible to implement given that each Braintree transaction seems to require a payment nonce? If not, can anyone suggest an alternative solution?
Much thanks.
To answer your question in your title in one sentence: NO, a payment nonce is NOT required for every transaction with Braintree.
Theoretically, it can be done by vaulting your buyer's payment method information into your Braintree account, and then charge with the vaulted payment method. A payment method is vaulted in Braintree with a token. The payment method token can then be used to make payments without requiring the buyer to be present.
However, the buyer must grant the payment method to you. This is typically done by the buyer providing his/her payment method information to you via a dropin form or a custom form, which returns a nonce and the information to you. This requires the buyer to be present.
I would suggest following the steps below of the Reference section of Braintree (https://developers.braintreepayments.com)
Transaction (how to make a basic one-time transaction)
Customer
Credit Card
Transaction (how to make a transaction without buyer presence)
PS, I said "theoretically" at the beginning, because if you can / cannot do it with vaulting, depends on your purchasing flow and also if your buyers are willing to do it that way.
PS again, vaulted payment method token can be used this way (in PHP):
Braintree_Transaction::sale(array(
'amount' => '10.00',
'paymentMethodToken' => $the_payment_method_token,
'options' => array(
'submitForSettlement' => true
)
));
For every Braintree transactions payment method nonce is not required. Buyer provides his/her information through dropin form or custom form, which returns the payment nonce method, we send the information to the braintree and get the payment_method_token. Written in python.
#login_required
def clienttoken(request):
result = braintree.Customer.create({
"first_name": "XXXX",
"last_name": "XXX",
"company": "XXX",
"email": "XXXX",
"phone": "312.555.1234",
"fax": "614.555.5678",
"website": "www.example.com",
"credit_card": {
"cardholder_name": "XXX",
"number": "XXXX",
"expiration_date": "XXX",
"options": {
"verify_card": True,
},
},
})
client_token = braintree.ClientToken.generate({"customer_id": result.customer.id})
request.session['customer_id'] = result.customer.id
return render(request, "braintree/checkout.html", {"client_token": client_token})
#csrf_exempt
def checkout(request):
customer_id = request.session['customer_id']
nonce = request.POST['payment_method_nonce']
result = braintree.PaymentMethod.create({
"customer_id": customer_id,
"payment_method_nonce": nonce,
"options": {
"verify_card": True,
}
})
return HttpResponse(result.payment_method.token)
We use payment_method_token for every transaction of braintree.
result = braintree.Transaction.sale({
"amount": "400",
"payment_method_token": "token",
"options": {
"submit_for_settlement": "true",
}
})
I'd like to use this endpoint to display the calculated fees on my site before taking the user to the paypal site; however, when I query the endpoint with a valid payKey, I receive an internal error.
Endpoint: https://developer.paypal.com/docs/classic/api/adaptive-payments/GetPrePaymentDisclosure_API_Operation/
To generate the payKey, I'm POSTing to svcs.sandbox.paypal.com/AdapativePayments/Pay with the following request body:
{
"actionType":"PAY",
"currencyCode":"USD",
"feesPayer":"SENDER",
"requestEnvelope": { "errorLanguage": "en_US" },
"cancelUrl":"test.com/cancel",
"returnUrl":"test.com/return",
"receiverList": {
"receiver": [
{ "email": "someguy#email.com", "amount": "80.00" }
]
}
}
Any ideas as to what's going on?
Note: I had to edit out the valid URLs because I don't have enough reputation.
For GetPrePaymentDisclosure you must supply senderEmail in the PAY request for it to function.
This is because GetPrePaymentDisclosure is supposed to be used to determine the status of the transaction and see if it is covered by the Remittance Transfer Rule.
From the Documentation: This API is specific for merchants who must support the Consumer Financial Protection Bureau's Remittance Transfer Rule.
It does not work to determine the fees beforehand if it does not hit these rules. As all you will get back is [status] => NON_RTR with no information.
If you would like this functionality outside of RTR transactions you should submit a feature request on PayPal's Technical Support Site
I'm trying to get the whole PayPal AdaptivePayments#Pay working, that part works. I pass a bunch of stuff in, get a paykey, which I pass to the approval url:
{returnUrl: urls[:return],
cancelUrl: urls[:cancel],
requestEnvelope: {errorLanguage: "en_GB"},
currencyCode: "GBP",
trackingId: self.id,
receiverList: {
receiver: [{email: Rails.configuration.site_paypal, amount: self.amount, primary: true},
{email: self.provider.paypal_email, amount: self.amount, primary: false}]
},
actionType: "PAY",
ipnNotificationUrl: urls[:ipn]}
The server comes back with everything correctly, I redirect to the url, it works, I get the payment in my PayPal sandbox account for Rails.configuration.site_paypal and in the IPN history I see the message but I have no way to identify it as it doesn't contain a paykey or trackingId :(
transaction_subject=
txn_type=web_accept
payment_date=10:06:09 Aug 17, 2012 PDT
last_name=Baldry
residence_country=GB
item_name=
payment_gross=
mc_currency=GBP
business=<Rails.configuration.site_paypal>
payment_type=instant
protection_eligibility=Ineligible
verify_sign=Asu0z613h-fyw8CNuZEjSsMXS58PAi46SzR3IvXXTX5JUizhF8vV4z25
payer_status=verified
test_ipn=1
tax=0.00
payer_email=<customer#email.com>
txn_id=9M582867K79935008
quantity=0
receiver_email=<Rails.configuration.site_paypal>
first_name=Michael
payer_id=M7U3UVA3E65VY
receiver_id=375R229JBE3TY
item_number=
payment_status=Completed
mc_gross=157.00
custom=
charset=windows-1252
notify_version=3.6
ipn_track_id=c9fcf587d770f
What am I doing wrong? Ripping my hair out...
Thanks
There are two types of IPN's
One is generated for the account that receives the money, based on their profile settings (It looks like that is the one you are getting)
The other is generated for the API caller (who may or may not be financially involved in the transaction). The API caller's IPN will include the PayKey.
If the API caller, and one of the receivers are the same, Make sure that you can either differentiate between the two IPN's you will receive, or that you have separate URL's for each. (The API callers is specified when making the API call, the receiver's is specified on the PayPal profile)