Paypal REST API: Payouts API giving error INSUFFICIENT_FUNDS in sandbox - paypal

I am trying to test the payouts API using the Node.js SDK for paypal and the example they have provided on Github. Here is the code for the same:
"use strict";
let paypal = require('paypal-rest-sdk');
const bluebird = require('bluebird');
paypal.configure({
mode: process.env.PAYPAL_MODE, //sandbox or live
client_id: process.env.PAYPAL_CLIENT_ID,
client_secret: process.env.PAYPAL_CLIENT_SECRET
});
bluebird.promisifyAll(paypal.payment);
bluebird.promisifyAll(paypal.payout);
function sendMoneyToParticipant () {
const sender_batch_id = Math.random().toString(36).substring(9);
let create_payout_json = {
"sender_batch_header": {
"sender_batch_id": sender_batch_id,
"email_subject": "You have a payment"
},
"items": [
{
"recipient_type": "EMAIL",
"amount": {
"value": 0.90,
"currency": "USD"
},
"receiver": "redacted-email-address",
"note": "Thank you.",
"sender_item_id": "item_3"
}
]
};
const sync_mode = 'true';
return paypal.payout.createAsync(create_payout_json, sync_mode)
}
PaypalAPI.sendMoneyToParticipant().then(result => {
console.log(JSON.stringify(result, null, 2))
}).catch(console.error)
I created the sandbox account myself and added $1000 during account creation step. However, I am still getting following as the response
{
"batch_header": {
"payout_batch_id": "78AMS3QCSQTBE",
"batch_status": "DENIED",
"time_created": "2017-05-28T07:38:51Z",
"time_completed": "2017-05-28T07:38:52Z",
"sender_batch_header": {
"email_subject": "You have a payment",
"sender_batch_id": "618ak0vozjwwhilik9"
},
"amount": {
"currency": "USD",
"value": "0.9"
},
"fees": {
"currency": "USD",
"value": "0.25"
}
},
"items": [
{
"payout_item_id": "F2XACBBTKRXK2",
"transaction_status": "FAILED",
"payout_item_fee": {
"currency": "USD",
"value": "0.25"
},
"payout_batch_id": "78AMS3QCSQTBE",
"payout_item": {
"amount": {
"currency": "USD",
"value": "0.9"
},
"note": "Thank you.",
"receiver": "mandeep.s.gulati#gmail.com",
"recipient_type": "EMAIL",
"sender_item_id": "item_3"
},
"errors": {
"name": "INSUFFICIENT_FUNDS",
"message": "Sender has insufficient funds",
"information_link": "https://developer.paypal.com/docs/api/payments.payouts-batch/#errors"
},
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/payments/payouts-item/F2XACBBTKRXK2",
"rel": "item",
"method": "GET"
}
]
}
],
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/payments/payouts/78AMS3QCSQTBE",
"rel": "self",
"method": "GET"
}
],
"httpStatusCode": 201
}

Related

PayPal subscription approval link throws an error

I am using Postman for this. It generates the following link https://www.sandbox.paypal.com/webapps/billing/subscriptions?ba_token=BA-79D58732NX9686808 however when I visit it, I see the following error message:
Things don't appear to be working at the moment. Please try again later.
After getting a token, I created a product then I created a plan and finally, I created a subscription. Am I missing something?
Here is what I have done and the response I have received:
Create Product:
{
"id": "FF-SUBSCRIPTION-SERVICE-BASIC-T1",
"name": "Subscription Basic Plan",
"description": "Basic Service Subscription Plan",
"type": "SERVICE"
}
Create Plan:
{
"product_id": "FF-SUBSCRIPTION-SERVICE-BASIC-T1",
"name": "Subscription Basic Plan",
"description": "Basic Service Subscription Plan",
"status": "ACTIVE",
"payment_preferences": {
"auto_bill_outstanding": true,
"payment_failure_threshold": 5
},
"billing_cycles": [
{
"frequency": {
"interval_unit": "MONTH",
"interval_count": 1
},
"tenure_type": "TRIAL",
"sequence": 1,
"total_cycles": 1
},
{
"frequency": {
"interval_unit": "MONTH",
"interval_count": 1
},
"tenure_type": "REGULAR",
"sequence": 2,
"total_cycles": 0,
"pricing_scheme": {
"fixed_price": {
"value": "14.99",
"currency_code": "USD"
}
}
}
]
}
Create Subscription:
{
"plan_id": "P-1DM03386YX156733CMNORKJQ",
"quantity": "1",
"shipping_amount": {
"currency_code": "USD",
"value": "14.99"
},
"subscriber": {
"name": {
"given_name": "John",
"surname": "Doe"
},
"email_address": "sb-xahhi21980157#personal.example.com"
}
},
"application_context": {
"brand_name": "X",
"locale": "en-US",
"shipping_preference": "SET_PROVIDED_ADDRESS",
"user_action": "SUBSCRIBE_NOW",
"payment_method": {
"payer_selected": "PAYPAL",
"payee_preferred": "IMMEDIATE_PAYMENT_REQUIRED"
},
"return_url": "https://www.example.com/returnUrl",
"cancel_url": "https://www.example.com/cancelUrl"
}
}
The response I receive is as follows:
{
"status": "APPROVAL_PENDING",
"id": "I-N6DFDLTU8HK9",
"create_time": "2022-10-29T11:58:28Z",
"links": [
{
"href": "https://www.sandbox.paypal.com/webapps/billing/subscriptions?ba_token=BA-79D58732NX9686808",
"rel": "approve",
"method": "GET"
},
{
"href": "https://api-m.sandbox.paypal.com/v1/billing/subscriptions/I-N6DFDLTU8HK9",
"rel": "edit",
"method": "PATCH"
},
{
"href": "https://api-m.sandbox.paypal.com/v1/billing/subscriptions/I-N6DFDLTU8HK9",
"rel": "self",
"method": "GET"
}
]
}

PayPal REST Api not returning exchange_rate

I have got a PayPal Advanced Checkout Sandbox set up and capturing the order using the API call below:
/v2/checkout/orders/{{order_id}}/capture
Below are the transaction details I send to create the order:
{
"intent": "CAPTURE",
"payer": {
"address": {
"admin_area_2": "Downton",
"postal_code": "SP5",
"country_code": "GB"
}
},
"purchase_units": [
{
"description": "Test Item",
"custom_id": "12345",
"soft_descriptor": "Purchase Descriptior",
"amount": {
"currency_code": "USD",
"value": "58.80",
"breakdown": {
"item_total": {
"currency_code": "USD",
"value": "49.00"
},
"tax_total": {
"currency_code": "USD",
"value": "9.80"
}
}
},
"items": [
{
"name": "Test Item",
"unit_amount": {
"currency_code": "USD",
"value": "49.00"
},
"tax": {
"currency_code": "USD",
"value": "9.80"
},
"quantity": 1,
"category": "PHYSICAL_GOODS"
}
],
"shipping": {}
}
]
}
And then once it has been paid with a sandbox personal account the order capture response is below:
{
"id": "4FS9138999682320N",
"status": "COMPLETED",
"payment_source": {
"paypal": {
"email_address": "sb-bdd43g21513704#personal.example.com",
"account_id": "V7ZN4NEJRLGZA",
"name": {
"given_name": "John",
"surname": "Doe"
},
"address": {
"country_code": "GB"
}
}
},
"purchase_units": [
{
"reference_id": "default",
"shipping": {
"name": {
"full_name": "John Doe"
},
"address": {
"address_line_1": "Whittaker House",
"address_line_2": "2 Whittaker Avenue",
"admin_area_2": "Richmond",
"admin_area_1": "Surrey",
"postal_code": "TW9 1EH",
"country_code": "GB"
}
},
"payments": {
"captures": [
{
"id": "40V95236PS9814847",
"status": "COMPLETED",
"amount": {
"currency_code": "USD",
"value": "58.80"
},
"final_capture": true,
"seller_protection": {
"status": "ELIGIBLE",
"dispute_categories": [
"ITEM_NOT_RECEIVED",
"UNAUTHORIZED_TRANSACTION"
]
},
"seller_receivable_breakdown": {
"gross_amount": {
"currency_code": "USD",
"value": "58.80"
},
"paypal_fee": {
"currency_code": "USD",
"value": "2.30"
},
"net_amount": {
"currency_code": "USD",
"value": "56.50"
}
},
"custom_id": "12345",
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/payments/captures/40V95236PS9814847",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v2/payments/captures/40V95236PS9814847/refund",
"rel": "refund",
"method": "POST"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/4FS9138999682320N",
"rel": "up",
"method": "GET"
}
],
"create_time": "2022-10-31T16:42:07Z",
"update_time": "2022-10-31T16:42:07Z"
}
]
}
}
],
"payer": {
"name": {
"given_name": "John",
"surname": "Doe"
},
"email_address": "sb-bdd43g21513704#personal.example.com",
"payer_id": "V7ZN4NEJRLGZA",
"address": {
"country_code": "GB"
}
},
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/4FS9138999682320N",
"rel": "self",
"method": "GET"
}
]
}
I get a status: COMPLETED as the response but it is not returning the exchange_rate value even though the payer currency is different to the payee currency.
Does anyone know why this is?
The example is a USD transaction, the payee account received USD.
If the payer used a funding source of a different currency to fund the transaction, this will not be visible to the receiver or API facilitator. Any such sender currency conversion is between the payer and PayPal; all you know (and all you need to know) is you received the requested USD amount via PayPal.

Paypal disputes sandbox testing, trigger CUSTOMER.DISPUTE.RESOLVED event

I am trying to trigger CUSTOMER.DISPUTE.RESOLVED event for disputes testing in sandbox, for that i made a test payment and opened a dispute in the resolution center. To trigger dispute resolved event i wanna call settle dispute method https://developer.paypal.com/docs/api/customer-disputes/v1#disputes-actions_adjudicate.
However i am not able to do that, cuz after create dispute is in WAITING_FOR_SELLER_RESPONSE status and i allowed only to call accept claim and provide evidence.
After accept claim i am able only to call provide supporting info method, settle method is still not allowed.
So my question is how to trigger CUSTOMER.DISPUTE.RESOLVED event in sandbox and on what dispute state i need to call settle method from here https://developer.paypal.com/docs/api/customer-disputes/v1#disputes-actions_adjudicate?
Request/Response examples
Dispute details right after open
{
"dispute_id": "PP-D-40523",
"create_time": "2021-03-03T08:47:08.000Z",
"update_time": "2021-03-03T08:48:12.000Z",
"disputed_transactions": [
{
"buyer_transaction_id": "35703532VD052404F",
"seller_transaction_id": "92198049S8582070N",
"create_time": "2021-03-03T08:41:55.000Z",
"transaction_status": "COMPLETED",
"gross_amount": {
"currency_code": "USD",
"value": "29.99"
},
"buyer": {
"name": "John Doe"
},
"seller": {
"email": "sb-47flty3787626#business.example.com",
"merchant_id": "TQNC9P6W9822C",
"name": "John Doe's Test Store"
},
"items": [],
"seller_protection_eligible": true
}
],
"reason": "UNAUTHORISED",
"status": "WAITING_FOR_SELLER_RESPONSE",
"dispute_amount": {
"currency_code": "USD",
"value": "29.99"
},
"dispute_life_cycle_stage": "CHARGEBACK",
"dispute_channel": "INTERNAL",
"extensions": {
"buyer_contacted_time": "2021-02-11T17:50:48.000Z"
},
"seller_response_due_date": "2021-03-24T08:47:50.000Z",
"allowed_response_options": {
"accept_claim": {
"accept_claim_types": [
"REFUND"
]
}
},
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/customer/disputes/PP-D-40523",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v1/customer/disputes/PP-D-40523/provide-evidence",
"rel": "provide_evidence",
"method": "POST"
},
{
"href": "https://api.sandbox.paypal.com/v1/customer/disputes/PP-D-40523/accept-claim",
"rel": "accept_claim",
"method": "POST"
}
]
}
After provide evidence
{
"dispute_id": "PP-D-40523",
"create_time": "2021-03-03T08:47:08.000Z",
"update_time": "2021-03-03T11:01:55.000Z",
"disputed_transactions": [
{
"buyer_transaction_id": "35703532VD052404F",
"seller_transaction_id": "92198049S8582070N",
"create_time": "2021-03-03T08:41:55.000Z",
"transaction_status": "COMPLETED",
"gross_amount": {
"currency_code": "USD",
"value": "29.99"
},
"buyer": {
"name": "John Doe"
},
"seller": {
"email": "sb-47flty3787626#business.example.com",
"merchant_id": "TQNC9P6W9822C",
"name": "John Doe's Test Store"
},
"items": [],
"seller_protection_eligible": true
}
],
"reason": "UNAUTHORISED",
"status": "UNDER_REVIEW",
"dispute_amount": {
"currency_code": "USD",
"value": "29.99"
},
"dispute_life_cycle_stage": "CHARGEBACK",
"dispute_channel": "INTERNAL",
"extensions": {
"buyer_contacted_time": "2021-02-11T17:50:48.000Z"
},
"evidences": [
{
"evidence_type": "OTHER",
"documents": [
{
"name": "ava.jpeg"
}
],
"notes": "Test",
"source": "SUBMITTED_BY_SELLER",
"date": "2021-03-03T11:01:56.000Z",
"action_info": {
"action": "PROVIDE_EVIDENCE"
}
}
],
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/customer/disputes/PP-D-40523",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v1/customer/disputes/PP-D-40523/provide-supporting-info",
"rel": "provide_supporting_info",
"method": "POST"
}
]
}
Another dispute after claim
{
"dispute_id": "PP-D-40407",
"create_time": "2021-03-02T08:17:07.000Z",
"update_time": "2021-03-02T08:47:05.000Z",
"disputed_transactions": [
{
"buyer_transaction_id": "1VS7234539684123P",
"seller_transaction_id": "2S50928513331053U",
"create_time": "2021-03-02T08:09:49.000Z",
"transaction_status": "COMPLETED",
"gross_amount": {
"currency_code": "USD",
"value": "29.99"
},
"buyer": {
"name": "John Doe"
},
"seller": {
"email": "sb-47flty3787626#business.example.com",
"merchant_id": "TQNC9P6W9822C",
"name": "John Doe's Test Store"
},
"items": [],
"seller_protection_eligible": true
}
],
"reason": "UNAUTHORISED",
"status": "UNDER_REVIEW",
"dispute_amount": {
"currency_code": "USD",
"value": "29.99"
},
"dispute_life_cycle_stage": "CHARGEBACK",
"dispute_channel": "INTERNAL",
"extensions": {
"buyer_contacted_time": "2021-02-11T17:50:48.000Z"
},
"evidences": [
{
"evidence_type": "OTHER",
"documents": [],
"notes": "Refund.",
"source": "SUBMITTED_BY_SELLER",
"date": "2021-03-02T08:47:06.000Z",
"action_info": {
"action": "ACCEPT_CLAIM",
"response_option": "REFUND"
}
}
],
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/customer/disputes/PP-D-40407",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v1/customer/disputes/PP-D-40407/provide-supporting-info",
"rel": "provide_supporting_info",
"method": "POST"
}
]
}
Adjudicate on dispute with evidence
Request
POST https://api.sandbox.paypal.com/v1/customer/disputes/PP-D-40523/adjudicate
{
"adjudication_outcome": "BUYER_FAVOR"
}
Response
{
"name": "VALIDATION_ERROR",
"message": "Invalid request - see details",
"debug_id": "6aadbbc916b3c",
"information_link": "https://developer.paypal.com/docs/api/customer-disputes/v1/#errors",
"details": [
{
"issue": "ACTION_NOT_ALLOWED_IN_CURRENT_DISPUTE_STATE"
}
],
"links": []
}
You have to get it to an 'UNDER_REVIEW' by PayPal state before you can trigger the adjudication one way or the other.
So if it is 'WAITING_FOR_SELLER_RESPONSE' you should provide evidence; there is a call for that.
You may also need to make an offer and deny the offer, or escalate to claim.
This tool may be useful for understanding the potential steps: https://www.paypal.com/apex/product-profile/customerDisputes/

PayPal express checkout: how should I check if the transaction is done and money is transferred?

I have PayPal express checkout on the client side and after the callback is fired with payment ID I want to check that id on the NodeJS side. I make a call to RESTfull API using JS SDK:
https://developer.paypal.com/docs/api/payments/v1/#payment_get
and I get such object below.
state is approved but transactions[0].related_resources[0].sale.state === pending
So how should I check if the transaction is done and money is transferred to the seller to activate the service he/she paid for?
from the callback, I have buyer email, payerId, paymentID, paymentToken so maybe I need some other endpoint?
{
"id": "PAY-7SN4959762125513LLPOWTDA",
"intent": "sale",
"state": "approved",
"cart": "2A9434180T1061602",
"payer": {
"payment_method": "paypal",
"status": "VERIFIED",
"payer_info": {
"email": "pp-test#gmail.com",
"first_name": "Some",
"last_name": "Surname",
"payer_id": "E76V3DRUQZYZW",
"shipping_address": {
"recipient_name": "Some Surname"
},
"phone": "0455346902",
"country_code": "FR"
}
},
"transactions": [
{
"amount": {
"total": "27.96",
"currency": "EUR",
"details": {
"subtotal": "27.96"
}
},
"payee": {
"merchant_id": "FJ96CP2E7QWMY"
},
"description": "The payment for services.",
"custom": "ws-1XWCLNRbVdWavMVZgH2cSE",
"invoice_number": "in-1h7KSgdCh35Gdpi_Yk7PO_",
"item_list": {
"items": [],
"shipping_address": {
"recipient_name": "Some Surname"
}
},
"related_resources": [
{
"sale": {
"id": "7UB08136N5814360K",
"state": "pending",
"amount": {
"total": "27.96",
"currency": "EUR",
"details": {
"subtotal": "27.96"
}
},
"payment_mode": "INSTANT_TRANSFER",
"reason_code": "RECEIVING_PREFERENCE_MANDATES_MANUAL_ACTION",
"protection_eligibility": "ELIGIBLE",
"protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE",
"parent_payment": "PAY-7SN4959762125513LLPOWTDA",
"create_time": "2018-11-03T09:25:53Z",
"update_time": "2018-11-03T09:25:53Z",
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/payments/sale/7UB08136N5814360K",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v1/payments/sale/7UB08136N5814360K/refund",
"rel": "refund",
"method": "POST"
},
{
"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-7SN4959762125513LLPOWTDA",
"rel": "parent_payment",
"method": "GET"
}
]
}
}
]
}
],
"create_time": "2018-11-03T09:25:32Z",
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-7SN4959762125513LLPOWTDA",
"rel": "self",
"method": "GET"
}
],
"httpStatusCode": 200
}
That's what I finally found out:
The "approved" state just means the buyer logged into their account
and approved the payment. You still need to execute the payment
request, which once you do check the "state" shown in the
"related_resources" section and it should say "completed", which
indicates the transaction amount has been captured. The "id" shown
below is the transaction identifier.
https://www.paypal-community.com/t5/REST-APIs/IPN-vs-actions-payment-execute-result/td-p/1564037
<PayPalButtons
createOrder = {async(data, actions) => {
return actions.order.create({
purchase_units: [
{
amount: {
value:'value',
},
},
],
});
}}
onApprove = {async (data, actions) => {
//Ignore Capture on Client side and do it on server
//Send Data to Server (mostly data.orderId and data.accessToken)
}}
/>
// Backend
const fetch = require('node-fetch');
// capture Function
const capturePayment = async (orderId, accessToken) => { //orderId and accessToken from frontend
const url = 'https://api-m.sandbox.paypal.com/v2/checkout/orders/${orderId}/capture';
const response = await fetch(url,{
method:"post",
headers: {
"Content-Type": "application/json",
Authorization:`Bearer ${accessToken}`,
},
});
const data = await response.json();
console.log(data)
return data;
}

INTERNAL_SERVICE_ERROR on PayPal order pay

Question updated - more details added.
I get a 500 (INTERNAL_SERVICE_ERROR) error from PayPal when I try to pay for an order.
I get ok from create order, and get the orderID - order status CREATED.
The order is approved by buyer - successfully and order status become APPROVED.
Order created by https://api.sandbox.paypal.com/v1/checkout/orders
Approved using paypal https://www.paypalobjects.com/api/checkout.js
{
"id": "53T50821FM697283T",
"gross_total_amount": {
"value": "26.66",
"currency": "ILS"
},
"purchase_units": [
{
"reference_id": "20180318-64466",
"amount": {
"currency": "ILS",
"total": "26.66"
},
"payee": {
"email": "d0535318380-classeeks#gmail.com"
},
"items": [
{
"name": "Meeting",
"sku": "20180318-64466",
"description": "Meeting 1/26/2018 1:00 AM-1/26/2018 2:20 AM. aaaaa",
"price": "26.66",
"currency": "ILS",
"quantity": 1
}
],
"shipping_address": {
"recipient_name": "Andrey Dyachenko",
"line1": "ישראליס 5 דירה 4",
"city": "תל-אביב",
"country_code": "IL",
"postal_code": "61014",
"state": "",
"type": "HOME_OR_WORK"
},
"partner_fee_details": {
"receiver": {
"email": "d0535318380-reciver#gmail.com"
},
"amount": {
"value": "12.66",
"currency": "ILS"
}
}
}
],
"payer_info": {
"email": "d0535318380-buyer#gmail.com",
"first_name": "Andrey",
"last_name": "Dyachenko",
"payer_id": "BZDA9RCZXKYQY",
"country_code": "IL",
"shipping_address": {
"recipient_name": "Andrey Dyachenko",
"line1": "ישראליס 5 דירה 4",
"city": "תל-אביב",
"country_code": "IL",
"postal_code": "61014",
"state": "",
"type": "HOME_OR_WORK"
}
},
"metadata": {
"supplementary_data": [
{
"name": "risk_correlation_id",
"value": "53T50821FM697283T"
},
{
"name": "buyer_ipaddress",
"value": "109.65.134.129"
},
{
"name": "external_channel",
"value": "WEB"
}
]
},
"redirect_urls": {
"return_url": "https://classeeks.com/order/details/70368c93-90db-4a8e-bd82-6d611acc2d17",
"cancel_url": "https://classeeks.com/order/details/70368c93-90db-4a8e-bd82-6d611acc2d17"
},
"create_time": "2018-03-18T19:49:11Z",
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/checkout/orders/53T50821FM697283T",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v1/checkout/orders/53T50821FM697283T/capture",
"rel": "capture",
"method": "POST"
}
],
"status": "APPROVED"
}
Next step pay with https://api.sandbox.paypal.com/v1/checkout/orders/53T50821FM697283T/pay
{ "disbursement_mode":"DELAYED" }
Response
{
"name": "INTERNAL_SERVICE_ERROR",
"message": "The server encountered an internal error that prevented it from fulfilling this request.",
"information_link": "https://developer.paypal.com/docs/api/#INTERNAL_SERVICE_ERROR",
"debug_id": "be0c6976ab17a"
}
Based https://demo.paypal.com/us/demo/go?page=cart
If you have created the order successfully, then you can either capture the order directly or create the authorization which places the fund on hold and later you can capture the authorization. Check the doc for PayPal order APIs.