Paypal create payment-tokens API return 422 Unprocessable Entity - paypal

I am using my paypal sandbox, and I am trying to use v2/vault/payment-tokens API to tokenize a credit card
Url:https://api.sandbox.paypal.com/v2/vault/payment-tokens
Method: POST
RequestBody(fake credit card that sandbox generated):
{
"source": {
"card": {
"number": "40320382525xxxx",
"expiry": "2022-11"
}
}
}
I can make sure that my sandbox have full scopes, my access token is right.
Below is the response:
{
"name": "UNPROCESSABLE_ENTITY",
"message": "The requested action could not be performed, semantically incorrect, or failed business validation.",
"debug_id": "15c1b3e9d8161",
"details": [
{
"issue": "UNKNOWN_BUSINESS_ERROR",
"description": "There was an issue while processing your request."
}
],
"links": [
{
"href": "https://developer.paypal.com/docs/api/vault/v2/#error-UNKNOWN_BUSINESS_ERROR",
"rel": "information_link",
"method": "GET"
}
]
}
Does any one meet the same issue?

Will you have permissions to use /v2/vault/payment-tokens in live mode? This API shouldn't be integrated without guidance from PayPal
Try using a test credit card from https://developers.braintreepayments.com/guides/credit-cards/testing-go-live/node

Related

RESOURCE_NOT_FOUND post request from Postman v2/payments/authorizations/{authorization_id}/void

Trying to call post request from Postman
www.sandbox.paypal.com/v2/payments/authorizations/{authorization_id}/void
getting below response error:
{
"name": "RESOURCE_NOT_FOUND",
"message": "The specified resource does not exist.",
"debug_id": "e5eafe26bbc24",
"details": [
{
"issue": "INVALID_RESOURCE_ID",
"field": "authorization_id",
"value": "72J58097UL3794703",
"description": "Specified resource ID does not exist. Please check the resource ID and try again.",
"location": "path"
}
],
"links": [
{
"href": "https://developer.paypal.com/docs/api/payments/v2/#error-INVALID_RESOURCE_ID",
"rel": "information_link"
}
]
}
The RESOURCE_NOT_FOUND error occurs when the resource specified in the request path (72J58097UL3794703, in this case) is not valid for the specified operation. The most likely explanations are that 72J58097UL3794703 is from a different environment (live, not sandbox) or that it is something like an Order ID or capture ID, rather than an authorization ID.
Orders and captures cannot be voided. If you are not going to use an Order ID, forget it and do not capture nor authorize it. In the case of a capture, it's already finalized so you can refund it.

Why the data of paypal webhook notify, event_type and resource.status do not match

I simplified the data structure received from paypal callback, why event_type is PAYMENT.CAPTURE.COMPLETED but resource.status is PENDING
{
"id": "xxxx",
"event_version": "1.0",
"create_time": "2022-05-30T06:17:22.994Z",
"resource_type": "capture",
"resource_version": "2.0",
"event_type": "PAYMENT.CAPTURE.COMPLETED",
// ...
"resource": {
"id": "xxxx",
"status": "PENDING",
"status_details": {
"reason": "PENDING_REVIEW"
}
// ...
},
}
Captured PayPal payments can be under review for many reasons. If the webhook's details aren't enough for you, examine the payment in www.paypal.com and/or have one of the account owners contact PayPal's support.

Cannot capture sandbox PayPal payment

I am currently trying the Orders API of PayPal using Postman, but cannot capture any payment.
For now, I could get the access token, set it to a collection variable, then created orders using (note the access token is set in the Authorization tab):
POST https://api-m.sandbox.paypal.com/v2/checkout/orders
Body:
{
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "10.00"
}
}
]
}
The request was successful with response body:
{
"id": "<random-id>",
"status": "CREATED",
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/<random-id>",
"rel": "self",
"method": "GET"
},
{
"href": "https://www.sandbox.paypal.com/checkoutnow?token=<random-id>",
"rel": "approve",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/<random-id>",
"rel": "update",
"method": "PATCH"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/<random-id>/capture",
"rel": "capture",
"method": "POST"
}
]
}
Then I proceeded to rel:approve's link using a browser https://www.sandbox.paypal.com/checkoutnow?token=<random-id> and signed in with my sandbox account. It shows me the usual payment window but when I pressed the "Continue" button, it tried to redirect to the return page but instead, refreshed the page itself.
When I tryed to check the order using rel:self's link: GET https://api.sandbox.paypal.com/v2/checkout/orders/<random-id>. It correctly showed the sandbox account's shipping details (name and address), but the status remained CREATED (not APPROVED or COMPLETED):
{
"id": "<random-id>",
"intent": "CAPTURE",
"status": "CREATED",
"purchase_units": [
{
"reference_id": "default",
"amount": {
"currency_code": "USD",
"value": "10.00"
},
"payee": {
"email_address": "<payee-email>",
"merchant_id": "<payee-id>"
},
"shipping": {
"name": {
"full_name": "<payer-name>"
},
"address": {
"address_line_1": "<payer-address-1>",
"address_line_2": "<payer-address-2>",
"admin_area_2": "<payer-address-3>",
"admin_area_1": "<payer-address-4>",
"postal_code": "<payer-address-5>",
"country_code": "<payer-address-6>"
}
}
}
],
"create_time": "<time-of-post-request>",
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/<random-id>",
"rel": "self",
"method": "GET"
},
{
"href": "https://www.sandbox.paypal.com/checkoutnow?token=<random-id>",
"rel": "approve",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/<random-id>",
"rel": "update",
"method": "PATCH"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/<random-id>/capture",
"rel": "capture",
"method": "POST"
}
]
}
When I tried to capture the payment using rel:caputure's link: POST https://api.sandbox.paypal.com/v2/checkout/orders/<random-id>/capture with header Content Type: application/json and empty body, it said "payer has not approved the Order for payment", despite I getting the shipping details from the GET request before:
{
"name": "UNPROCESSABLE_ENTITY",
"details": [
{
"issue": "ORDER_NOT_APPROVED",
"description": "Payer has not yet approved the Order for payment. Please redirect the payer to the 'rel':'approve' url returned as part of the HATEOAS links within the Create Order call or provide a valid payment_source in the request."
}
],
"message": "The requested action could not be performed, semantically incorrect, or failed business validation.",
"debug_id": "6a10ea489ffce",
"links": [
{
"href": "https://developer.paypal.com/docs/api/orders/v2/#error-ORDER_NOT_APPROVED",
"rel": "information_link",
"method": "GET"
}
]
}
I have three questions:
Was I using the Orders API correctly? Did I miss some HTTP requests and/or some crucial steps?
I had the return URL set for my sandbox application, why did the payment page not redirect me but instead refreshed itself? Did I miss some setup beforehand?
Why did I fail to capture the payment like above?
P.S. After some digging I think I might be missing the authorize payment step but I have no idea how to do it. (Client-side request? Server-side request?)
I proceeded to rel:approve's link .. when I pressed the "Continue" button, it tried to redirect to the return page but instead, refreshed the page itself.
You did not specify a return_url , so there is nowhere to return to. Refreshing is all that can be done.
What you should do is not redirect to an approval URL, and integrate with no redirects. For this 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). The latter one should (on success) store the payment details in your database before it does the return (particularly purchase_units[0].payments.captures[0].id, the PayPal transaction ID)
Pair those two routes with the following approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
I was also having trouble with this issue, I solved it by expanding the request body, much like #preston-phx said, with the return URL, and it looked something like this:
{
"intent": "CAPTURE",
"payer": {
"email_address": requestBody.payer_email
},
"purchase_units": [{
"amount": {
"currency_code": "USD",
"value": requestBody.amount
},
"payee": {
"email_address": requestBody.payee_email
},
"payment_instruction": {
"disbursement_mode": "INSTANT", // can be INSTANT or DELAYED
"platform_fees": [
{
"amount": {
"currency_code": "USD",
"value": calculateFeesFromAmount(requestBody.amount)
}
}
]
}
}],
"redirect_urls": {
"return_url": "https://example.com/paypalpay/order/approved",
"cancel_url": "https://example.com/paypalpay/order/cancelled"
},
"application_context": {
"brand_name": "Header for payment page",
"locale": "en-US",
"landing_page": "BILLING", // can be NO_PREFERENCE, LOGIN, BILLING
"shipping_preference": "NO_SHIPPING" // because I didn't want shipping info on the page,
"user_action": "PAY_NOW", // Button name, can be PAY_NOW or CONTINUE
"return_url": "https://example.com/paypalpay/order/approved",
"cancel_url": "https://example.com/paypalpay/order/cancelled"
}
}
This also helped me customise the payment page to an extent. I hope Paypal folks include these in the docs at the correct places, most of devs have to dig through a lot of documentation to create an extensive, usable request body.

PayPal Server SDK: how to approve an order ID

I was trying to implement paypal api for one of my projects
I am using sandbox environment and server side sdk
In the request i have
{
"intent": "CAPTURE",
"application_context": {
"brand_name": "EXAMPLE INC",
"landing_page": "BILLING",
"shipping_preference": "SET_PROVIDED_ADDRESS",
"user_action": "PAY_NOW"
},
i.e
"intent": "CAPTURE"
"user_action": "PAY_NOW"
I created an order using the api OrdersCreateRequest(). In the response i get the
result.id = "IDVALUE"
result.status = "CREATED"
and also the links
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/XXXXXXXX",
"method": "GET",
"rel": "self"
},
{
"href": "https://www.sandbox.paypal.com/checkoutnow?token=XXXXXXXXXX",
"method": "GET",
"rel": "approve"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/XXXXXXXXXXXXXX",
"method": "PATCH",
"rel": "update"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/XXXXXXXXXXXXXX/capture",
"method": "POST",
"rel": "capture"
}
],
I have tried to open the url
{
"href": "https://www.sandbox.paypal.com/checkoutnow?token=XXXXXXXXXX",
"method": "GET",
"rel": "approve"
},
In the browser, it asks for PayPal login, what credentials we have to use as login and password. I have only client_id and client_secret
How to get an approved order id. What should I do now.
The next step is to redirect the payer to that approval_url or use the Order ID with Smart Payment Buttons, which is better than redirecting. Either way the payer will be signing in with their PayPal (sandbox) buyer account or entering their (sandbox) buyer information in a PayPal window or form.
The best approval flow to use is the one at https://developer.paypal.com/demo/checkout/#/pattern/server
Note that it pairs with two routes on your server, one that creates the order and one that captures the order after approval.
How to get the username and the password for the sandbox account.
Navigate to
And we see the email and password which can used to as paypal login credentials while approve the order
So now go to the approve url https://www.sandbox.paypal.com/checkoutnow?token=XXXXXXXXXX
and click on login (paypal account) and enter email and password
And after successful login pay here
So now the order gets approved.

PayPal REST API: how to do an immediate payment and without asking for shipping address

I'm trying to use PayPal REST API instead of PayPal Classic API but it seems that the REST API is lacking two features that the Classic API has:
immediate payment: when the user goes to PayPal page show him a "Pay now" button instead of a "Continue" button and "You’re almost done. You will confirm your payment on ..." phrase.
no shipping address: avoid asking the user to confirm his shipping address while on PayPal page (in Classic API is done with NOSHIPPING=1 parameter, if I remember well)
So my question is: is it possibile do perform an immediate payment without asking for shipping address using REST API? Do I have to go back to Classic API?
I provide here a little more informations about how I'm using the PayPal REST API.
I'm using the PayPal REST Java SDK.
This is a sample request:
{
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"transactions": [
{
"amount": {
"currency": "USD",
"total": "5",
"details": {
"subtotal": "5"
}
},
"description": "This is the payment transaction description.",
"item_list": {
"items": [
{
"quantity": "1",
"name": "Item 1",
"price": "5",
"currency": "USD"
}
]
}
}
],
"redirect_urls": {
"return_url": "http://XXX/handlePayment.jsp?guid\u003dXXX",
"cancel_url": "http://XXX/cancelPayment.jsp?guid\u003dXXX"
}
}
And its response:
{
"id": "XXX",
"create_time": "2014-06-29T08:52:55Z",
"update_time": "2014-06-29T08:52:55Z",
"state": "created",
"intent": "sale",
"payer": {
"payment_method": "paypal",
"payer_info": {
"shipping_address": {}
}
},
"transactions": [
{
"amount": {
"total": "5.00",
"currency": "USD",
"details": {
"subtotal": "5.00"
}
},
"description": "This is the payment transaction description.",
"item_list": {
"items": [
{
"name": "Item 1",
"price": "5.00",
"currency": "USD",
"quantity": "1"
}
]
}
}
],
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/payments/payment/XXX",
"rel": "self",
"method": "GET"
},
{
"href": "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=XXX",
"rel": "approval_url",
"method": "REDIRECT"
},
{
"href": "https://api.sandbox.paypal.com/v1/payments/payment/XXX/execute",
"rel": "execute",
"method": "POST"
}
]
}
While delving through the REST API I came across this
I believe this means you don't have to go about creating any "Profiles" as such, and can just pass them along with the payment call...
Further explanation as requested :)
Below is an example of passing PayPal experience parameters along with a particular payment call using the Client-side JS method for Express checkout.
payment: function(data, actions) {
return actions.payment.create({
payment: {
transactions: [
{
amount: { total: '1.00', currency: 'USD' }
}
]
},
experience: {
input_fields: {
no_shipping: 1
}
}
});
},
Hope that makes enough sense to you guys! :)
Unfortunately, the REST API is still a long ways behind the Classic API with features it provides. These features you mentioned are things I've seen come up quite a bit, and to my knowledge they are not yet available with the REST services.
I personally have stuck with Classic as they provide everything and I really see no advantage to using REST myself. If you happen to be working with PHP (which I always do) you may be interested in my class library for PayPal. It makes all of the Classic API calls very quick and easy for you, and it's available on Packagist so you can use with Composer easily.
The REST API now supports no-shipping with the Payment Experience APIs.
You need to create a web experience profile and supply no_shipping as an input field. Then use the profile ID when creating the payment.
The profile ID doesn't need to be recreated every time.
appreciate that this post hasn't had any activity for a while but...
i hit on the exact same problem and used this post as a start point for my own question:
paypal api: take immediate payment without a shipping address
it's taken a bit of trial and error but i you can create a one off web profile with 'no_shipping' set to 1, store the id that it creates and then pass that in with future payments that don't require a shipping address.
still haven't figured out how to get rid of the 'You're almost done. You will confirm your payment on xxx.' but my payment process is a far better place than it was!
hope this helps someone out there as this no shipping issue is one that a lot of people appear to be hitting with the paypal api...
I tried using the experience section of the API and apart from still not being able to force a locale code have been able to disable shipping and go straight to billing:
payment: {
transactions: [{
invoice_number: document.getElementById("ReqTxt").value,
amount: {
total: document.getElementById("InvoiceAmt").innerText,
currency: document.getElementById("Currency").innerText
}
}]
},
experience: {
input_fields: {
no_shipping: 1
},
flow_config: {
landing_page_type:'billing'
}
}
you can also see this page. It is possible to set the user action in the flow_config section too
For 'Pay Now' instead of 'Continue' on Paypal I use a special param in approval url:
$approvalUrl = $payment->getApprovalLink().'&useraction=commit';
Result:
https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=TOKEN&useraction=commit