I have been trying to implement split payments using the Paypal Adaptive Payments API. I have got a simple parallel payment to work, however this shows both split payments to the buyer.
Basically I am selling a membership. Our local association should get 75% of the funds and 25% is passed on to the governing body. The member should only see the total amount as being a 2015 membership so I started to look into chained payments instead. This on the face of it looks like a very simple code change but is causing me issues in relation to unilateral payments.
I am implementing this in php.
So here is the paypal send method
function PaypalSend($payment_details, $api_function){
// initial endpoint that starts the transaction
$paypalInitialEndpoint = 'https://svcs.sandbox.paypal.com/AdaptivePayments/';
// set http headers
$headers = array(
'Connection: Close',
'X-PAYPAL-SECURITY-USERID: testseller_api1.nipf.com',
'X-PAYPAL-SECURITY-PASSWORD: 1381912839',
'X-PAYPAL-SECURITY-SIGNATURE: AzykGe5AzfK.mJFMRzBwIcTap-LcAsmsP4AhYzk1Y-07mh-xPLc-goK3',
'X-PAYPAL-APPLICATION-ID: APP-80W284485P519543T',
'X-PAYPAL-REQUEST-DATA-FORMAT: JSON',
'X-PAYPAL-RESPONSE-DATA-FORMAT: JSON'
);
// setup curl request and http headers
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $paypalInitialEndpoint . $api_function);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payment_details));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
if(!($res = curl_exec($ch)) )
{
error_log(curl_error($ch));
curl_close($ch);
exit;
}
curl_close($ch);
return json_decode($res, TRUE);
}
And here is my chained payment method. This code needs a lot of refactoring but was fully functional with the parallel payments with only minor changes to this current code.
function sendChainedPayment(){
$purchase_details_array = array(
"actionType" => "PAY",
"currencyCode" => "GBP",
"feesPayer" => "PRIMARYRECEIVER",
"memo" => "blah blah blah",
"receiverList" => array(
"receiver" => array(
array(
"amount" => "30.00",
"email" => "testseller#nipf.com",
"primary" => "true"
),
array(
"amount" => "10.00",
"email" => "testseller#gbpf.com",
"primary" => "false"
)
)
),
"returnUrl" => "http://localhost/membershipSuccess.php",
"cancelUrl" => "http://localhost/membershipCancel.php",
"requestEnvelope" => array(
"errorLanguage" => "en_UK",
"detailLevel" => "ReturnAll"
)
);
$response = PaypalSend($purchase_details_array, "Pay");
//echo json_encode($response) . "<br /><br />";
$payKey = $response['payKey'];
$payment_details = array(
"requestEnvelope" => array(
"errorLanguage" => "en_UK",
"detailLevel" => "ReturnAll"
),
"payKey" => $payKey,
"receiverOptions" => array(
array(
"receiver" => array("email" => "testseller#nipf.com"),
"invoiceData" => array(
"item" => array(
array(
"name" => "Membership 2015",
"price" => "30.00",
"identifier" => "Membership 2015: joe bloggs"
)
)
)
),
array(
"receiver" => array("email" => "testseller#gbpf.com"),
"invoiceData" => array(
"item" => array(
array(
"name" => "Membership 2015 (Fee)",
"price" => "10.00",
"identifier" => "Membership 2015 (Fee): joe bloggs"
)
)
)
)
)
);
$response = PaypalSend($payment_details, "SetPaymentOptions");
//echo json_encode($response) . "<br /><br />";
$paypalCustomerUrl = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_ap-payment&paykey=' . $payKey;
echo $paypalCustomerUrl;
//header('Location: ' . $paypalCustomerUrl);
}
I am getting the following response JSON with the first callout. I think this is to do with the accounts being just sandbox accounts rather than real accounts but how am I meant to test this in the sandbox if the accounts all have to be real accounts? In this case the account used as the API account is the primary receiver.
{"responseEnvelope":{"timestamp":"2015-02-04T14:37:26.598-08:00","ack":"Failure","correlationId":"749bd1d709e76","build":"15089777"},"error":[{"errorId":"520009","domain":"PLATFORM","subdomain":"Application","severity":"Error","category":"Application","message":"Account Account not found. Unilateral receiver not allowed in chained payment is restricted","parameter":["Account not found. Unilateral receiver not allowed in chained payment"]}]}
I was getting the same error message, and I fixed it by making sure that the 2 email addresses that I was sending payments to in the API call were both sandbox accounts. They didn't exist as real email addresses, but they did need to exist as paypal accounts. (Previously I was sending them to 2 actual live paypal accounts that didn't exist in the sandbox).
Judging by the error message, "Account not found. Unilateral receiver not allowed in chained payment", it just can't find your account, probably because they are not sandbox accounts.
Related
I am new to doing anything with paypal, and it's frustrating to me. I am just trying to create the chained payment with this here using sandbox business account:
$api = "https://svcs.sandbox.paypal.com/AdaptivePayments/Pay";
$input = array(
"actionType" => "CREATE",
"currencyCode" => "USD",
"feesPayer" => "EACHRECEIVER",
"memo" => "TestNote",
"receiverList" => array(
"receiver" => array( //first goes to merchant(95% of payment)
"amount" => "95.00",
"email" => "rbxseller#gmail.com",
"primary" => true
),
"receiver" => array( //then sends 5% commission to owner of site
"amount" => "5.00",
"email" => "rbxowner#gmail.com",
"primary" => false
)
),
"requestEnvelope" => array(
"errorLanguage" => "en_US"
)
);
$headers = array(
"X-PAYPAL-SECURITY-USERID: ".USER_ID,
"X-PAYPAL-SECURITY-PASSWORD: ".USER_PASS,
"X-PAYPAL-SECURITY-SIGNATURE: ".USER_SIG,
"X-PAYPAL-REQUEST-DATA-FORMAT: NV",
"X-PAYPAL-RESPONSE-DATA-FORMAT: JSON",
"X-PAYPAL-APPLICATION-ID: APP-80W284485P519543T"
);
$ch = curl_init($api);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($input));
$response = curl_exec($ch);
var_dump($response);
I got the error response:
[{"errorId":"580001","domain":"PLATFORM","subdomain":"Application","severity":"Error","category":"Application","message":"Invalid request: {0}"}]
Thank you for taking time to reply!
You're not going to be able to simply submit an array of data to the PayPal end point. You'll need to build out an XML request for Adaptive Payments.
I would recommend you take a look at my PayPal PHP Class Library, which works in very much the same way you're trying to work here, except that it would take your array data, generate the XML request, send it to PayPal, parse the XML result and return an array back to you.
It supports all PayPal APIs including Adaptive Payments, and it comes with fully functional samples as well as ready-made template files to start fresh calls with.
I'm just trying to do a test with paypal chained payments, and it's really frustrating. My goal for this test is to send the primary receiver $15 and then $1 to a secondary receiver. Here is my code:
$api = "https://svcs.sandbox.paypal.com/AdaptivePayments/Pay";
$input = array(
"actionType" => "PAY",
"currencyCode" => "USD",
"feesPayer" => "EACHRECEIVER",
"cancelUrl" => "https://www.google.com", //test url
"returnUrl" => "https://www.google.com", //test url
"receiverList" => array(
"receiver" => array( //send primary receiver $15
"amount" => "15.00",
"email" => "rbxseller1#gmail.com",
"primary" => true
),
"receiver" => array( //send owner of site $1 commission
"amount" => "1.00",
"email" => "rbxowner#gmail.com",
"primary" => false
)
),
"requestEnvelope" => array(
"errorLanguage" => "en_US"
)
);
$headers = array(
"X-PAYPAL-SECURITY-USERID: ".USER_ID, //predefined
"X-PAYPAL-SECURITY-PASSWORD: ".USER_PASS, //predefined
"X-PAYPAL-SECURITY-SIGNATURE: ".USER_SIG, //predefined
"X-PAYPAL-REQUEST-DATA-FORMAT: JSON",
"X-PAYPAL-RESPONSE-DATA-FORMAT: JSON",
"X-PAYPAL-APPLICATION-ID: APP-80W284485P519543T"
);
$ch = curl_init($api);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($input));
$response = curl_exec($ch);
var_dump($response);
When I try to do this, it works, but in my payment details it only shows the $1 to the secondary receiver, there is no trace of the primary receiver:
{"paymentInfo":[{"receiver":{"amount":"1.00","email":"rbxowner#gmail.com","primary":"false","paymentType":"SERVICE","accountId":"6LBSVJQNVE9DA"},"pendingRefund":"false"}]}
I tried setting the "actionType" to "PAY_PRIMARY" and it gave me this error:
"message":"Invalid request parameter: action type PAY_PRIMARY can only be used in chained payments","parameter":["PAY_PRIMARY"]
It's getting quite frustrating as I've looked it up on youtube, stackoverflow, some forum websites, etc and haven't found much helpful info.
Thank you very much to anyone who will take the time to read this and help me!
Your mistake is in the PHP array syntax here:
"receiverList" => array(
"receiver" => array(/*primary receiver info*/),
"receiver" => array(/*secondary receiver info*/)
),
An associative array can only have one value for each key (to picture why, imagine accessing $receiverList['receiver'] from an array declared this way; it wouldn't know which you wanted).
To PHP, this is the same as writing $foo = 1; $foo = 2; and expecting both 1 and 2 to still be "there" somewhere. So all that gets sent to Paypal is this:
"receiverList" => array(
"receiver" => array(/*secondary receiver info*/)
),
You can see this for yourself if you echo out json_encode($input).
I don't know what the array should look like, but it's definitely not that. My best guess without seeing the documentation would be a simple list with no keys specified:
"receiverList" => array(
array(/*primary receiver info*/),
array(/*secondary receiver info*/)
),
Or possibly the "recevier" key needs to be there, and the two entries are inside that:
"receiverList" => array(
"receiver" => array(
array(/*primary receiver info*/),
array(/*secondary receiver info*/)
)
),
Or perhaps you've misread the docs and there is no "receiverList" key, only "receiver":
"receiver" => array(
array(/*primary receiver info*/),
array(/*secondary receiver info*/)
),
Whichever variant it is, there's no point changing the rest of your query until you get this bit right, because right now you are only sending one set of receiver details to Paypal.
I want to perform an implicit payment from my account (the paypal api signed one) into another (or multiple as parallel payment).
I decided to use Adaptive Payments and have implemented the function to call the Pay action as follows
$bodyparams = array (
"requestEnvelope.errorLanguage" => "en_US",
'actionType' => 'PAY',
'currencyCode' => 'USD',
'receiverList.receiver(0).email' => 'receiver#domain.com',
'receiverList.receiver(0).amount' => '1.00',
'senderEmail' => 'myaccount#domain.com',
'memo' => 'Test memo',
'ipnNotificationUrl' => 'http://google.com',
'cancelUrl' => 'http://google.com',
'returnUrl' => 'http://google.com'
);
$url = "https://svcs.paypal.com/AdaptivePayments/Pay";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X-PAYPAL-SECURITY-USERID: XXX',
'X-PAYPAL-SECURITY-PASSWORD: XXX',
'X-PAYPAL-SECURITY-SIGNATURE: XXX',
'X-PAYPAL-REQUEST-DATA-FORMAT: NV',
'X-PAYPAL-RESPONSE-DATA-FORMAT: JSON',
'X-PAYPAL-APPLICATION-ID: APP-XXX',
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($bodyparams));
$response = json_decode(curl_exec($ch));
$pk="";
if(isset($response->responseEnvelope) && $response->responseEnvelope->ack == "Success"){
$pk = $response->payKey;
}else{
die(var_dump($response));
}
$ch = curl_init();
header("Location: https://www.paypal.com/cgi-bin/webscr?cmd=_ap-payment&paykey=".$pk);
die();
Paypal returns me "You do not have permission to execute this payment implicitly"
{
"responseEnvelope": {
"timestamp": "2016-05-19T10:05:05.407-07:00",
"ack": "Failure",
"correlationId": "22e0930fcae7d",
"build": "20420247"
},
"error": [
{
"errorId": "550001",
"domain": "PLATFORM",
"subdomain": "Application",
"severity": "Error",
"category": "Application",
"message": "You do not have permission to execute this payment implicitly"
}
]
}
But when I switch the 2 accounts (i.e. just for test, the other account sends me the money), I get redirected to the approval process.
Now, the app I am using has the flag as shown in the picture below
What should I check? It seems that paypal doesn't allow me to send implicit payments, but don't know for what reason (paypal support were not be able to say anything else then give me some links).
IMPORTANT EDIT
If I use the sandbox credentials, the payment is "COMPLETED"
I am using Stripe Connect for stripe integration. In this, we firstly create a managed account under an existing stripe account. Then we charge the customer and the charge is transferred to one account and application fee to the managed account. By creating a managed account, we get the account id associated to it using:
$acc=\Stripe\Account::create(
array(
"country" => "US",
"managed" => true
)
);
Then we charge customer and link two accounts with that charge using application fee concept as follows:
$c_charge = \Stripe\Charge::create(
array(
"amount" => 1000, // amount in cents
"currency" => "usd",
"source" => {TOKEN OF CUSTOMER},
"description" => "Example charge",
"application_fee" => 123 // amount in cents
),
array("stripe_account" => 'acct_15rTMLISz4VN6mw2')
);
In this case since the stripe account with which the application fee is linked has no bank account connected for money transfer, so now we need to link the bank account with the stripe account
Following code is based on it, but it generates an error: Invalid token id
$data=array(
'bank_account'=> $token
);
$pHttp_headers=array(
"Content-Type: application/x-www-form-urlencoded",
"Authorization: Bearer {$stripe['secret_key']}"
);
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,"https://api.stripe.com/v1/accounts/acct_15rTMLISz4VN6mw2/bank_accounts");
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $pHttp_headers);
//curl_setopt($ch, CURLOPT_USERPWD,$stripe['secret_key']);
$pResult = curl_exec($ch);
curl_close($ch);
$pResult=json_decode($pResult,true);
This is the error I am getting:
Array ( [error] => Array ( [type] => invalid_request_error [message] => Invalid token id: tok_15rlFFHPiBMaAbxH6hwPNcDL [param] => bank_account ) )
Any ideas?
I am trying to send push notification through push woosh such like this :
is anybody help me how to send push notification on device from this code
function pwCall(
'createMessage', array(
'application' => PW_APPLICATION,
'auth' => PW_AUTH,
"devices" => PW_DEVICETOKEN,
'notifications' => array(
'send_date' =>'now', //gmdate('d-m-Y H:i', strtotime('2014-04-07 20:35')),
'content' => 'my custom notification testing ',
'link' => 'http://pushwoosh.com/',
'content' => array("en" => "English","ru" =>"Русский","de"=>"Deutsch")
),
'page_id' => 16863,
'link' => 'http://google.com',
'data' => array( 'custom' => 'json data' ),
)
);
I am getting error such as
Array ( [status_code] => 210 [status_message] => Cannot parse date [response] => )
notifications should be array of objects in JSON notation. In PHP it will be array of arrays. This is because you can create multiple notifications in one request.
final JSON for notifications field:
"notifications":[{ ... notification properties... }, { ... second notification properties ... }, ...]
There are only 3 root parameters in request: application(OR applications_group), auth, and notifications. Other parameters are parameters of notification, not request.
Finally your PHP call should be like following:
pwCall("createMessage", array(
"auth" => PW_AUTH,
"application" => PW_APPLICATION,
"notifications" => array(
array(
"send_date" => "now",
"content" => array("en" => "English", "ru" =>"Русский", "de"=>"Deutsch"),
"link" => "http://pushwoosh.com/",
"page_id" => 16863,
"devices" => array( PW_DEVICETOKEN ),
"data" => array( "custom" => "json data" )
)
)
));
All notification's fields except of send_date and content are optional and can be omited
By the looks of it, your date is not formatted correctly. You're passing an ordinary string consisting of the word "now". What you'll want to do is something along the lines of the following:
function pwCall("createMessage", array(
"application" => PW_APPLICATION,
"auth" => PW_AUTH,
"devices" => PW_DEVICETOKEN,
"notifications" => array(
"send_date" => gmdate("Y-m-d H:i"),
"content" => "My custom notification",
"link" => "http://pushwoosh.com/",
"content" => array("en" => "English", "ru" =>"Русский", "de"=>"Deutsch")
),
"page_i" => 16863,
"link" => "http://google.com",
"data" => array("custom" => "json data"),
)
);
we've developped an API to easily call the Pushwoosh Web Services.
This API should be a good quality one and is fully tested (very high code coverage).
https://github.com/gomoob/php-pushwoosh
$push_auth = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$push_app_id = 'XXXXX-XXXXX';
$push_debug = false;
$title = ''; // pushwoosh title
$banner = ''; // pushwoosh banner
$send_date = 'now'; // pushwoosh date
$android_header = ''; // pushwoosh android header
$android_custom_icon = '' pushwoosh notification icon;
sendpush('createMessage', array(
'application' => $push_app_id,
'auth' => $push_auth,
'notifications' => array(
array(
'send_date' => $send_date,
'content' => $title,
'android_header'=>$android_header,
'android_custom_icon' =>$android_custom_icon,
'android_badges' => 2,
'android_vibration' => 1,
'android_priority' => 1,
'data' => array('custom' => 'json data'),
),
)
));
function sendpush($method, $data) {
$url = 'https://cp.pushwoosh.com/json/1.3/' . $method;
$request = json_encode(['request' => $data]);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if (defined('PW_DEBUG') && self::$push_de) {
print "[PW] request: $request\n";
print "[PW] response: $response\n";
print "[PW] info: " . print_r($info, true);
}
return $info;
}
}