Issue while trying to implement Paypal Create Order API - php

About the issue
This is about create order api in Paypal. Documentation link is here I am trying to pass below payload, so that the request could have my return and cancel url and everything works perfectly.
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "100.00"
}
}
],
"application_context" => [
"return_url" => "my return url",
"cancel_url" => "my cancel url"
]
Just the return and cancel url has gone deprerated in application_context.
To overcome this problem, I removed application_context from payload and added payment_source like below which has return and cancel url
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "100.00"
}
}
],
"payment_source": {
"paypal": {
"experience_context": {
"return_url": "return Url",
"cancel_url": "cancel Url"
}
}
}
Now, it gives an error message - PAYPAL_REQUEST_ID_REQUIRED
I need to pass return and cancel url and at this stage I only need to create the request to let user go to checkout page. that's it. I really don't have any payment info yet.

To resolve the error message "PAYPAL_REQUEST_ID_REQUIRED", you need to including a unique identifier in the "request_id" field in the payload.
something like:
[
"intent":"CAPTURE",
"purchase_units":[
{
"amount":{
"currency_code":"USD",
"value":"100.00"
}
}
],
"payment_source":{
"paypal":{
"experience_context":{
"return_url":"return Url",
"cancel_url":"cancel Url"
}
}
},
"request_id":"UNIQUE_REQUEST_ID"
]
You may also verify that the return and cancel URLs provided in the payload are valid and accessible.

Inside your payment_source add "request_id": "YOUR_UNIQUE_REQUEST_ID"
Your system can generate this request Id yourself and must be unique to prevent getting error message DUPLICATED_REQUEST_ID
See here in documentation https://developer.paypal.com/api/rest/requests
PayPal-Request-Id
"Optional. Contains a unique user-generated ID that the server stores for a period of time. Use this header to enforce idempotency on REST API POST calls. ...."

You need request_id could you try including reference_id.
{
"intent": "CAPTURE",
"purchase_units": [
{
"reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",
"amount": {
"currency_code": "USD",
"value": "100.00"
}
}
],
"payment_source": {
"paypal": {
"experience_context": {
"return_url": "https://example.com/returnUrl",
"cancel_url": "https://example.com/cancelUrl"
}
}
}
}'

https://developer.paypal.com/api/rest/reference/orders/v2/errors/
PAYPAL_REQUEST_ID_REQUIRED: A PayPal-Request-Id is required if you are trying to process payment for an Order. Please specify a PayPal-Request-Id or Create the Order without a payment_source specified.
Add this param in your headers
PayPal-Request-Id
string [ 1 .. 36 ] characters
The server stores keys for 6 hours. The API callers can request the times to up to 72 hours by speaking to their Account Manager.

Related

PayPal Smart buttons patch order via PHP API

I'm implementing Smart Buttons with Express checkout, so customers can select the delivery address on Paypal's popup. As agreed with Paypal support, I'm doing the communication with Paypal servers via PHP instead of Javascript. So in the onShippingChange event, I'm calling my server to calculate the delivery price and patch the order so Paypal updates the delivery price. The success path works fine, I need your help on error case(s).
How the patch request shall look like to instrument Paypal to display the warning that my webshop is not delivering to the selected location? (When implementing on Javascript, this was the return actions.reject in the onShippingChange.)
Thanks!
This is the patch request of a successful patch:
{
"path": "/v2/checkout/orders/xxxxxxxxxxxxxxxxxxxxx?",
"body": [
{
"op": "replace",
"path": "/intent",
"value": "CAPTURE"
},
{
"op": "replace",
"path": "/purchase_units/#reference_id=='default'/amount",
"value": {
"currency_code": "GBP",
"value": 265.95,
"breakdown": {
"item_total": {
"currency_code": "GBP",
"value": 236
},
"shipping": {
"currency_code": "GBP",
"value": 29.95
}
}
}
}
],
"verb": "PATCH",
"headers": {
"Content-Type": "application/json"
}
}
in the onShippingChange event, I'm calling my server to calculate the delivery price and patch the order
Great. But if the address is unsupported, your server must return the failed status in its response to that call. Based on that response, onShippingChange must return actions.reject() to the calling PayPal JS.

PHP Quickbooks SDK - Batch requests and handling failures

I've building out a small app that connects to a Quickbooks API via an SDK. The SDK provides batch operations to help reduce the number of API requests needed.
However, I'm hoping to make a large amount of requests (ie: bulk deletes, uploads in the 100s/1000s). I've gotten the deletes to work, however, now I'm hoping to integrate Laravel's Queue system so that any items in the $batch that fail (due to these business-rules or other reasons) are sent to a worker who will reattempt them after waiting a minute .
Below is an example of a delete request.
class QuickBooksAPIController extends Controller
{
public function batchDelete(Request $request, $category)
{
$chunks = array_chunk($request->data, 30);
foreach ($chunks as $key => $value) {
$batch[$key] = $this->dataService()->CreateNewBatch();
foreach ($value as $id) {
$item = $this->dataService()->FindById($category, $id);
$batch[$key]->AddEntity($item, $id, "delete");
}
$batch[$key]->Execute();
}
return response()->json(['message' => 'Items Deleted'], 200);
}
}
The documentations are a bit sparse for my scenario though. How can I get the failed batch items on order to try again?
Is using batches even the right choice here? Because I have to hit the API anyway to get the $item... which doesn't make sense to me (I think I'm doing something wrong there).
EDIT:
I intentionally sent out a request with more then 30 items and this is the failure message. Which doesn't have the values that didn't make the cut.
EDIT#2:
Ended up using array_chunk to separate the payload into 30 items (which is the limit of the API). Doing so helps process many requests. I've adjusted my code above to represent my current code.
How can I get the failed batch items on order to try again?
If you look at Intuit's documentation, you can see that the HTTP response the API returns contains this information. Here's the example request they show:
{
"BatchItemRequest": [
{
"bId": "bid1",
"Vendor": {
"DisplayName": "Smith Family Store"
},
"operation": "create"
},
{
"bId": "bid2",
"operation": "delete",
"Invoice": {
"SyncToken": "0",
"Id": "129"
}
},
{
"SalesReceipt": {
"PrivateNote": "A private note.",
"SyncToken": "0",
"domain": "QBO",
"Id": "11",
"sparse": true
},
"bId": "bid3",
"operation": "update"
},
{
"Query": "select * from SalesReceipt where TotalAmt > '300.00'",
"bId": "bid4"
}
]
}
And the corresponding response:
{
"BatchItemResponse": [
{
"Fault": {
"type": "ValidationFault",
"Error": [
{
"Message": "Duplicate Name Exists Error",
"code": "6240",
"Detail": "The name supplied already exists. : Another customer, vendor or employee is already using this \nname. Please use a different name.",
"element": ""
}
]
},
"bId": "bid1"
},
{
"Fault": {
"type": "ValidationFault",
"Error": [
{
"Message": "Object Not Found",
"code": "610",
"Detail": "Object Not Found : Something you're trying to use has been made inactive. Check the fields with accounts, customers, items, vendors or employees.",
"element": ""
}
]
},
"bId": "bid2"
},
{
"Fault": {
"type": "ValidationFault",
"Error": [
{
"Message": "Stale Object Error",
"code": "5010",
"Detail": "Stale Object Error : You and root were working on this at the same time. root finished before you did, so your work was not saved.",
"element": ""
}
]
},
"bId": "bid3"
},
{
"bId": "bid4",
"QueryResponse": {
"SalesReceipt": [
{
"TxnDate": "2015-08-25",
"domain": "QBO",
"CurrencyRef": {
"name": "United States Dollar",
"value": "USD"
},
"PrintStatus": "NotSet",
"PaymentRefNum": "10264",
"TotalAmt": 337.5,
"Line": [
{
"Description": "Custom Design",
"DetailType": "SalesItemLineDetail",
"SalesItemLineDetail": {
"TaxCodeRef": {
"value": "NON"
},
"Qty": 4.5,
"UnitPrice": 75,
"ItemRef": {
"name": "Design",
"value": "4"
}
},
"LineNum": 1,
"Amount": 337.5,
"Id": "1"
},
{
"DetailType": "SubTotalLineDetail",
"Amount": 337.5,
"SubTotalLineDetail": {}
}
],
"ApplyTaxAfterDiscount": false,
"DocNumber": "1003",
"PrivateNote": "A private note.",
"sparse": false,
"DepositToAccountRef": {
"name": "Checking",
"value": "35"
},
"CustomerMemo": {
"value": "Thank you for your business and have a great day!"
},
"Balance": 0,
"CustomerRef": {
"name": "Dylan Sollfrank",
"value": "6"
},
"TxnTaxDetail": {
"TotalTax": 0
},
"SyncToken": "1",
"PaymentMethodRef": {
"name": "Check",
"value": "2"
},
"EmailStatus": "NotSet",
"BillAddr": {
"Lat": "INVALID",
"Long": "INVALID",
"Id": "49",
"Line1": "Dylan Sollfrank"
},
"MetaData": {
"CreateTime": "2015-08-27T14:59:48-07:00",
"LastUpdatedTime": "2016-04-15T09:01:10-07:00"
},
"CustomField": [
{
"DefinitionId": "1",
"Type": "StringType",
"Name": "Crew #"
}
],
"Id": "11"
}
],
"startPosition": 1,
"maxResults": 1
}
}
],
"time": "2016-04-15T09:01:18.141-07:00"
}
Notice the separate response object for each request.
The bId value is a unique value you send in the request, which is then echo'd back to you in the response, so you can match up the requests you send with the responses you get back.
Here's the docs:
https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/batch#sample-batch-request
Is using batches even the right choice here?
Batches make a lot of sense when you are doing a lot of things all at once.
The way you're trying to use them is... weird. What you should probably be doing is:
Batch 1
- go find all your items
Batch 2
- delete all the items
Your existing code doesn't make sense because you're trying to both find the item and delete the item in the exact same batch HTTP request, which isn't possible via the API.
I intentionally sent out a request with more then 30 items and this is the failure message.
No, it's not. That's a PHP error message - you have an error in your code.
You need to fix the PHP error, and then look at the actual response you're getting back from the API.

"URL Can't Be Used" error in adding facebook post with child_attachments via api

i'm trying to make a post on facebook using api with using child_attachments param, so i can pass multiple urls in 1 post.
In facebook debugger i'm passing json like that
{
"message": "test debug",
"child_attachments": [
{
"link": {
"link": "https://google.com"
}
},
{
"link": {
"link": "https://ft.com"
}
}
]
}
but i'm getting following error message
{ "error": {
"message": "Invalid parameter",
"type": "OAuthException",
"code": 100,
"error_data": {
"blame_field_specs": [
[
"child_attachments[0][link]"
]
]
},
"error_subcode": 2061006,
"is_transient": false,
"error_user_title": "URL Can't Be Used",
"error_user_msg": "The URL you entered, \"https://google.com\" doesn't direct to a website. Please enter a valid URL and try again.",
"fbtrace_id": "xxxxxxxx"
}
}
i've tried setting urls in app domains , i tried use urls with / without https and with/without www.
still no luck, can some one give me some advise?
Thanks,
Roman.
ok, so i figured, the correct format should be like that:
{
"message": "message to post",
"link": "https://yahoo.com",
"child_attachments": [
{
"link": "https://yahoo.com",
"name": "name -1",
"picture": "https://images.all-free-download.com/images/graphiclarge/ethereal_image_185195.jpg"
},
{
"link": "https://google.com",
"name": "name - 2 ",
"picture": "https://images.all-free-download.com/images/graphiclarge/ethereal_image_185195.jpg"
}
]
}
note that even despite of the thing you adding links in the child_attachments, you must provide 'link' parameter also for post

[Dialogflow]Update Permission through Webhook format (for push notifications)

ORIGINAL REQUEST: I'm trying to implement the push notifications following the documentation: https://developers.google.com/actions/assistant/updates/notifications
I'm using Dialogflow with webhooks (in PHP) and the documentation is giving example in nodeJS
Right now, i'm blocked because of the Update permission, here's my Webhook response :
{
"source": "webhook",
"payload": {
"google": {
"expectUserResponse": true,
"systemIntent": {
"intent": "actions.intent.PERMISSION",
"data": {
"#type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
"permissions": [
"UPDATE"
]
},
"updatePermission": {
"intent": "notification.simple.text"
}
}
}
}
}
When I do the simulation, asks me a permission for a push, but not for the intent I specified.
I'm quiet sure that the problem is the updatePermission, something must be wrong with that:
Is it the field name?
In intent, i put the intent name that i filled in dialogflow, maybe do i have to an use action? Is it in the good format ?
If someone can help me or just give me an example of a clean response for an update permission.
Thanks!
Solution
I just found why, my json wasn't good, the updatePermissionValueSpec must be into data object.
{
"source": "webhook",
"payload": {
"google": {
"expectUserResponse": true,
"systemIntent": {
"intent": "actions.intent.PERMISSION",
"data": {
"#type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
"permissions": [
"UPDATE"
],
"updatePermissionValueSpec": {
"intent": "notification_simple_text"
}
}
}
}
}
}
I believe updatePermission should be named updatePermissionValueSpec.
Example response:
"payload": {
"google": {
"expectUserResponse": true,
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "PLACEHOLDER"
}
}
]
},
"systemIntent": {
"intent": "actions.intent.PERMISSION",
"data": {
"#type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
"permissions": [
"UPDATE"
],
"updatePermissionValueSpec": {
"intent": "intent_name"
}
}
}
}
}

Paypal Billing agreement, weird response

I have an issue dealing with the PayPal-PHP-SDK,
My problem is, i'm creating the plan and the agreement, everything is working fine,
I'm putting 30€ as a fee in the agreement and the plan :
$amont = 30 ; // Prix
$merchantPreferences->setReturnUrl("$baseUrl/paiement-accept.php")
->setCancelUrl("$baseUrl/paiement-cancel.php")
->setAutoBillAmount("yes")
->setInitialFailAmountAction("CONTINUE")
->setMaxFailAttempts("0")
->setSetupFee(new Currency(array('value' => $amont, 'currency' => $currency)));
The date i'm using to create it it's :
$date = date('Y-m-d\TH:i:s', time()+210) ."Z";`
$agreement->setName($name)
->setDescription($description)
->setStartDate($date);
I tried with time()+210 and using only now's timestamp.
I execute the agreement, and there is the answer :
{
"id": "I-VD24XJ8MG14N",
"state": "Pending",
"description": "Abonnement Mensuel - 30\u20ac/mois",
"plan": {
"payment_definitions": [
{
"type": "REGULAR",
"frequency": "Month",
"amount": {
"currency": "EUR",
"value": "30.00"
},
"cycles": "0",
"charge_models": [
{
"type": "TAX",
"amount": {
"currency": "EUR",
"value": "0.00"
}
},
{
"type": "SHIPPING",
"amount": {
"currency": "EUR",
"value": "0.00"
}
}
],
"frequency_interval": "1"
}
],
"merchant_preferences": {
"setup_fee": {
"currency": "EUR",
"value": "0.00"
},
"max_fail_attempts": "0",
"auto_bill_amount": "YES"
}
},
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/payments/billing-agreements/I-VD24XJ8MG14N/suspend",
"rel": "suspend",
"method": "POST"
},
{
"href": "https://api.sandbox.paypal.com/v1/payments/billing-agreements/I-VD24XJ8MG14N/re-activate",
"rel": "re_activate",
"method": "POST"
},
{
"href": "https://api.sandbox.paypal.com/v1/payments/billing-agreements/I-VD24XJ8MG14N/cancel",
"rel": "cancel",
"method": "POST"
},
{
"href": "https://api.sandbox.paypal.com/v1/payments/billing-agreements/I-VD24XJ8MG14N/bill-balance",
"rel": "self",
"method": "POST"
},
{
"href": "https://api.sandbox.paypal.com/v1/payments/billing-agreements/I-VD24XJ8MG14N/set-balance",
"rel": "self",
"method": "POST"
}
],
"start_date": "2014-11-21T23:00:00Z",
"agreement-details": {
"outstanding_balance": {
"currency": "EUR",
"value": "0.00"
},
"cycles_remaining": "0",
"cycles_completed": "0",
"final_payment_date": "1970-01-01T00:00:00Z",
"failed_payment_count": "0"
}
}
I don't know why the setup_fees are at 00
Why is start date at "2014-11-21T23:00:00Z"
And why is it the state Pending.
Can you help me how to make it work ? :(
If you need more informations (more code) to see where the problem is, ask me and i'll answer with more informations
Thanks a lot !
Xusifob
/***************************************************************************************************
EDIT :
****************************************************************************************************/
Thank you for taking the time of answering me.
For the date i changed it,
The payment method to create the billing agrement is a paypal account :
// Add Payer
$payer = new Payer();
$payer->setPaymentMethod('paypal');
$agreement->setPayer($payer);
I've already done all theses steps, click on the approval url, connect to my paypal test account and accept the transaction.
On my return page, I am on this page :
mywebsite/paiement-accept.php?token=EC-4VW6406102605853H
I've seen in the Paypal api that the ExecuteAgreement page is expecting a success value in the url ($_GET['success'] = true)
But i never got this value in my url, and the answer tell me that the User cancelled the Approval.
I changed the code not to have this error anymore and it gives me the response i put above.
This is my code :
$createdAgreement = require '../vendor/paypal/rest-api-sdk-php/sample/billing/ExecuteAgreement.php';
require '../vendor/paypal/rest-api-sdk-php/sample/billing/GetBillingAgreement.php';
And for the ExecuteAgreement :
if (isset($_GET['token'])) {
$token = $_GET['token'];
$agreement = new \PayPal\Api\Agreement();
try {
$agreement->execute($token, $apiContext);
} catch (Exception $ex) {
ResultPrinter::printError("Executed an Agreement", "Agreement", $agreement->getId(), $_GET['token'], $ex);
exit(1);
}
ResultPrinter::printResult("Executed an Agreement", "Agreement", $agreement->getId(), $_GET['token'], $agreement);
} else {
ResultPrinter::printResult("User Cancelled the Approval", null);
}
return $agreement;
Changing the date did not solve the problem with the start_date response issue
Thank you again for your help :)
For the date, you could use date('c', time()+210) as per http://php.net/manual/en/function.date.php
Would you mind answering the information as, what was the payment method while creating Billing Agrement. If you used PayPal, you need to click on the approval_url, and complete the flow.
Once done, you need to execute the payment, and then, when you do a get on the Agreement, you would be able to see the state as Active.
Let me know if that fixes this.

Categories