I'm integrating PayPal using PHP and cURL and managed to create orders and capture the payments via the https://api.sandbox.paypal.com/v2/checkout/orders and
https://api.sandbox.paypal.com/v2/checkout/orders/<order_id>/capture endpoints
The orders I'm trying to refund have been successfully captured and looking at the details it shows their status is "COMPLETED" and the final_capture field is true, so the order has been placed and I can see the transaction ended successfully in the merchant account
Now I'm trying to test refunds using the capture ID I get from the capture call but it always fails with an error with the following response body
{
"error":"invalid_subject",
"error_description":"Subject Authentication failed"
}
I tracked down the problem behind the Subject Authentication failed problem being a wrong Paypal-Auth-Assertion header, that I printed and double checked multiple times already and it seems to be right. Here's the code I use to make the call
// Codeigniter function to read from $_POST
$capture_id = $this->input->post('paypal_capture_id');
$auth_1 = base64_encode("{\"alg\":\"none\"}");
$auth_2 = base64_encode("{\"payer_id\":<payer_id>,\"iss\":<client_id>}");
$auth_assertion_header = $auth_1 . "." . $auth_2 . ".";
$curlSES=curl_init();
curl_setopt($curlSES,CURLOPT_URL,"https://api.sandbox.paypal.com/v2/payments/captures/$capture_id/refund");
curl_setopt($curlSES, CURLOPT_POST, true);
curl_setopt($curlSES, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Authorization: Bearer '. $access_token,
'PayPal-Auth-Assertion:' . $auth_assertion_header
));
curl_setopt($curlSES, CURLOPT_POSTFIELDS, '{}'); // empty payload means full refund
curl_setopt($curlSES, CURLOPT_RETURNTRANSFER, true);
$result=curl_exec($curlSES);
Where payer_id and client_id are filled using a merchant id account used for the sandbox environment and the client_id is the secret id for the application provided by Paypal, the $access_token has been previously generated from a function I use in other parts of the application and it works fine.
Furthermore, if I try to make the same call using Postman (and the PayPal API explorer as well) it produces a different error, that is
{
"error": "invalid_request",
"error_description": "No permissions to set target_client_id"
}
No search result for this error is really helpful so I'm lost on what I'm doing wrong there, although it doesn't seem related to the Paypal-Auth-Assertion as it falls back to the Subject Authentication failed error if I provide a wrong value on purpose.
I was facing the same issue, when trying to refund a captured order for a partner account. It seems to me u are using the string escaped json from the example.
Try using the json_encode function like below:
$header = base64_encode(json_encode(['alg' => 'none']));
$body = base64_encode(json_encode(['payer_id' => $merchantId, 'iss' => $clientId]));
$authHeader = $header . "." . $body . ".";
I was able to refund a captured order with this $authHeader.
Greetings
Related
I am working on Walmart integration to my own web application using PHP. When I tried to acknowledge my Mexico orders, I got an empty response. The data type of response is string with 0 length, error code 400. It looks like my credentials are good. Is "https://marketplace.walmartapis.com/v3/orders/{PurchaseOrderId}/acknowledge" a valid API url?
$url="https://marketplace.walmartapis.com/v3/orders/P108915403/acknowledge";
$ch = curl_init();
$qos = uniqid();
$options = array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
CURLOPT_HEADER => false,
CURLOPT_POST =>1,
CURLOPT_HTTPHEADER => array(
"WM_SVC.NAME: Walmart Marketplace",
"WM_QOS.CORRELATION_ID: $qos",
"Authorization: Basic $authorization",
"WM_SEC.ACCESS_TOKEN:$token",
"Accept: application/json",
"Content-Type: application/json",
"WM_MARKET: mx",
),
);
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
var_dump($response);
Code Snippet
After putting it aside for a few months, today I picked it up and finally got it resolved luckily and got a 202 Accepted Response with empty content(Walmart's documentation says the response to a successful call contains the acknowledged order, but it actually contains nothing except for 202 Accepted code).
When I tried to acknowledge my Mexico orders, the response is actually not empty. The header contains error message: http code 400 Bad Request. I confirmed that it is due to wrong payload structure after testing.
So "https://marketplace.walmartapis.com/v3/orders/{PurchaseOrderId}/acknowledge" is a valid API URL and is the same as US API. The difference between them is that MX site needs a well-structured payload through POST while US site does not(US API only needs an empty payload through POST).
The key point to a successful call is the structure of the payload. The structure should be like the samples in the documentation.
Pay attention to the details of the structure. Refer to the picture for the structure of payload here.
The "orderLine" and "orderLineStatus" should be declared as ARRAY instead of single element. And this is the reason why I failed to call the acknowledge API before.
Looks like you are using an old API, which has been discontinued, the same has been communicated late December 2020.
We have improved our onboarding experience with following steps:
Create an account on Walmart IO platform - https://walmart.io by clicking on the user icon just before the search box.
Login to the account and accept "Terms of Use"
Click on "Create Your Application" to create a new application and fill in appropriate details.
Use this tutorial to generate two sets of public/private keys - https://walmart.io/key-tutorial
* One set will be used for production.
* Other set will be used for stage.
Upload both public keys using - https://walmart.io/key-upload?app_name=<your app name>
Consumer ID will be generated for both sets for prod and stage which can be seen on the dashboard - https://walmart.io/userdashboard
Click on "Request Access" for Checkout APIs at https://walmart.io/reference and fill out the form.
Once the access is approved, documentation will be available for integrating with Commerce API through Walmart I/O.
We will send out client secrets for stage and prod as soon as they’re ready.
Thanks,
Firdos
IOSupport
In my PHP-based application, I've been using the Google oAuth 2 server-side flow for several years, and it has always worked flawlessly, until recently. I've been reading on any possible breaking API changes, but can't find any. Most questions having similar issues are several years old, so I'm asking a new question. It is particularly strange that this stopped working without any change on my end.
Below details are from my dev environment, but I'm getting similar results on production. This is the URL I use for getting the permission (not sure what the correct terminology is):
https://accounts.google.com/o/oauth2/auth?
scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&state=%2Fprofile
&redirect_uri=http%3A%2F%2Fwww.jungledragon.org%2Fapps%2Fjd4%2Fsignin%2Fgoogle%2Fcallback
&response_type=code
&client_id=652476484487.apps.googleusercontent.com
&approval_prompt=auto
This seems to work correctly. If not given already, the user indeed sees the Google screen to grant access. If the user then approves proceeds, they are redirected back to my application given the callback URL.
With permission given, the next goal is to get some user data. For this, the following code is used:
// get values from the callback URL
parse_str($_SERVER['QUERY_STRING'],$_GET);
$code = $_GET['code'];
$error = $_GET['error'];
$state = $_GET['state'];
// an error reason is returned, something went wrong
if ($error_reason) { return false; }
// our app is recognized, get access token by doing a post to the Google oAuth service
$url = 'https://accounts.google.com//o/oauth2/token';
$data =
"code=" . urlencode($code) .
"&client_id=" . $this->CI->config->item('pd_oauth_google_clientid') .
"&client_secret=" . $this->CI->config->item('pd_oauth_google_clientsecret') .
"&redirect_uri=" . urlencode($this->CI->config->item('pd_oauth_google_callbackurl')) .
"&grant_type=authorization_code";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
// check the result. anything but a 200 return code is an error
$info = curl_getinfo($ch,CURLINFO_HTTP_CODE);
if ($info!=200) { return false; }
As you can see, a CURL POST request is created with several parameters. None of the param values have changed and this has worked for years, yet now stopped working, for unknown reasons.
The particular problem is that the response of the post is the Google Error 404 (Not Found)!! page. This doesn't give me any meaningful info on what could be wrong.
Help is greatly appreciated, as this issue blocks all users on my production site that log in via Google authentication.
https://accounts.google.com//o/oauth2/token
will result in a 404
https://accounts.google.com/o/oauth2/token
will result in
{
"error" : "invalid_request"
}
No idea why your code worked for the last year you have an extra / in there
I am trying to get the express checkout token for a PayPal one time purchase integration. I get this error when trying to make the cURL request:
ACK=Failure&L_ERRORCODE0=81002&L_SHORTMESSAGE0=Unspecified%20Method&L_LONGMESSAGE0=Method%20Specified%20is%20not%20Supported&L_SEVERITYCODE0=Error1
Here is my code
<?php
if(!isset($_GET['id'])) {
header("Location: index.php");
exit();
}
//Get paypal express checkout token
$ch = curl_init("https://api-3t.sandbox.paypal.com/nvp");
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"USER: seller-v3rm_api1.test.com",
"PWD: <snip>",
"SIGNATURE: <snip>",
"METHOD: SetExpressCheckout",
"VERSION: 93",
"PAYMENTREQUEST_0_PAYMENTACTION: SALE",
"PAYMENTREQUEST_0_AMT: 25",
"PAYMENTREQUEST_0_CURRENCYCODE: USD",
"RETURNURL: http://test/buy.php",
"CANCELURL: http://test.com",
));
$token = curl_exec($ch);
echo $token;
Am i missing something?
You aren't setting up the request string correctly. I would really recommend taking a look at this PayPal PHP SDK.
First, it will eliminate your need to even mess with this sort of code because it handles it all for you. All you would need to do is open the SetExpressCheckout.php template file that it comes with and fill out the parameters, and then the same for the other calls you might use.
Also, though, if you want you could study the code to see how it's handling the cURL request. You need to build an actual NVP string (ie. &something=like&this=example). Then that is what you send to PayPal via cURL.
I am writing a PHP application that's supposed to allow users to add certain events to a private Google Calendar. The calendar is owned by me, and I need a way for PHP to communicate with the calendar API using fixed credentials (everyone can add events using a form on the website, but the calendar itself is not publicly visible).
From what I have read, this is possible using ClientLogin in the v1 API. In the v3 API, however, the available options are OAuth2.0 or the API key. Using the API key doesn't seem to work, since it can only be used for requests that don't require authorization, and OAuth doesn't seem right either, because users are not supposed to access their own calendars, but the one my application uses.
I thought about getting the OAuth token programatically, but that's bound to break sooner or later, since the OAuth dialog can use captchas.
This seems to be such a standard use case — a web application that lets users interact with a single calendar in some predefined ways — yet I can't find any documentation on how to make it happen in the v3 API. Can anyone help me?
I have found a solution that I think that is "the official" for what you want to do.
First, you have to activate a Google API "Client ID for installed applications".
Go to the Google API console and create the project.
Then, activate the calendar.
Go to the "API access" option, and use the "Create OAuth 2.0 client" button.
Give a name (and a logo, if you want) to the product. Click "next".
Choose the "Installed application" option and click "Create Client Id".
Now you have your access configurated. Now, you will need some codes. To obtain them:
*The "Authentication Code". To get it, you need the following information:
SCOPE: https://www.google.com/calendar/feeds/ (if you want to access the calendar API. There are others you can find them at the OAuth 2.0 Playground)
CLIENT_ID: You will find it at the API Access Section at the Google API Console.
REDIRECT_URI: Get it at the same place.
Now, copy the following code into a file, put the values into the variables, execute the code (php -q script_name.php), and go to the URL printed.
<?php
$scope = '';
$client_id = '';
$redirect_uri = '';
$params = array(
'response_type' => 'code',
'client_id' => $client_id,
'redirect_uri' => $redirect_uri,
'scope' => $scope
);
$url = 'https://accounts.google.com/o/oauth2/auth?' . http_build_query($params);
echo $url."\n";
?>
The web page will ask you to allow the access. Do it, and you will get a code, which is your Authentication Code.
*The "Refresh Code". To get it, you will need:
The data you used before, plus the "client secret" code in the API Console, between the "client id" and the "redirect URI".
As you did before, copy the following code, and put the variables in place (the code field is the Authentication Code).
Execute and the result is the "Refresh Token".
<?php
$url = 'https://accounts.google.com/o/oauth2/token';
$post_data = array(
'code' => '',
'client_id' => '',
'client_secret' => '',
'redirect_uri' => '',
'grant_type' => 'authorization_code',
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
$token = json_decode($result);
echo $token->refresh_token . "\n";
?>
At this moment, you have all you need. Be careful if one day you change the Authentication Code. You will have to get new keys.
To access a calendar service, here you have the example:
Change the variable values before using it.
This example gets the primary calendar events, but you can change the address for any in the calendar API (http://code.google.com/intl/ca/apis/calendar/v3/getting_started.html#background_operations)
<?php
$scope = 'https://www.google.com/calendar/feeds/';
$client_id = '';
$client_secret = '';
$redirect_uri = '';
$refresh_token = '';
$token_url = 'https://accounts.google.com/o/oauth2/token';
$post_data = array(
'client_secret' => $client_secret,
'grant_type' => 'refresh_token',
'refresh_token' => $refresh_token,
'client_id' => $client_id
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $token_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
$token_object = json_decode($result);
$access_token = $token_object->access_token;
// Get the results
$rest_url = 'https://www.googleapis.com/calendar/v3/calendars/primary/events';
$header = "Authorization: OAuth " . $access_token;
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, array($header));
curl_setopt($ch, CURLOPT_URL, $rest_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$rest_result = curl_exec($ch);
print_r(json_decode($rest_result));
?>
First, the script asks for an "Access Token", which is valid for an hour. Then, the script gets the REST service (any in the calendar scope), sending the access token in the header.
To give a best speed at the scrip, it would be good to store the access token in a cache until it's older than 3600 seconds. This way, the script would avoid one of the two calls.
Tips:
Visit OAuth 2.0 Playground to understand all the information sent in the OAuth process. It helped me a lot
A post by Eric Nagel in his blog gave me the solution. All the merit is to him. I can't link it since I haven't got enough "reputation".
You will need to use both the Developer Key (API Key) and OAuth2. The developer key authenticates who wrote the software and is used for things like quota which is on a per developer basis not a per user basis. OAuth2 is for user authentication and will be need to access the non-public calendar.
OAuth2 has a renew token from which you can generate a session token and this means that you will not need to screen scrape the OAuth screens to get authenticated. To get this I would write a little command line application, or you use a one off PHP page.
Under the Google Api Console go to API Access
Generate a new Client ID and choose Installed Application ( as you will be authenticating you server as you not as your user)
Either using a console app or a one off PHP page authenticate using OAuth and your google account (the one with the calendar you want access to)
In the return from the authentication there should be a renew token, (called renew or refresh or something similar). Save this string and make it available to your PHP site.
When you need to access the service your OAuth library should have a renew/refresh call. There is an example using .Net below.
private IAuthorizationState CreateAuthorization(NativeApplicationClient arg)
{
// Get the auth URL:
IAuthorizationState state = new AuthorizationState(new[] { AdsenseService.Scopes.AdsenseReadonly.GetStringValue() });
state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
if (refreshToken.IsNotNullOrEmpty()) // refreshToken you stored in step 4
{
try
{
state.RefreshToken = refreshToken;
if (arg.RefreshToken(state)) // This is calling out to the OAuth servers with the refresh token getting back a session token, returns true if successful.
{
if (state.RefreshToken != refreshToken) // if the refresh token has changed, save it.
{
PersistRefreshToken(authorization.RefreshToken);
}
return this.authorization = state; // Retain the authorization state, this is what will authenticate your calls.
}
}
catch (ProtocolException ex) {...}
The AuthorisationState that has now been renewed can then be used to authenticate call you make to the API. this state can be used many time until it expires and then can be refreshed. As you are authenticating your application as yourself not as a user this AuthorisationState can be shared by all you sessions. Both the current AuthorisationState and the refresh token should be kept securely on your server and never sent to the client, if you ever sent these as part of a response your clients would have the same privileges as your code application
Can also be used with the Google php library. The access token for the $client->setAccessToken() function has to be formatted in the following way:
$at= '{"access_token":"' . $access_token . '",' .
'"token_type":"Bearer",' .
'"expires_in":3600,' .
'"refresh_token":"' . $refresh_token . '",',
'"created":' . time() . '}';
Where $access_token is the access token found by you and $refresh_token is the refresh token. Tested with the useless simple.php google example.
Authentication is then just:
$client->setAccessToken($at);
I am using this example to successfuly make a login connection on windows live platform:
http://code.msdn.microsoft.com/messengerconnect
(the oauth handler callback one)
I receive a token and a user id from their api, but I can't seem to understand how to fetch the user profile from these info.
Does anyone know how to do this?
There are examples in MS website, but they are all C# or javascript ones and I have to do it in PHP.
After retrieving the token and the cid I tried this, but returns me an error:
$url_string = 'http://apis.live.net/V4.1/cid-'.$user->getId().'/Profiles/';
echo("<br/>\n".$url_string);
$curl_session = curl_init($url_string);
// build HTTP header with authorization code
$curl_options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => array(
'Authorization: WRAP access_token=AuthToken="'.urlencode($_REQUEST['stoken']).'"',
'Accept: application/json'
)
);
// setup options for curl transfer
curl_setopt_array($curl_session, $curl_options);
// execute session and get response
$curl_response = curl_exec($curl_session);
print $curl_response;
curl_close($curl_session);
The error is this:
{"Title":"ErrorResource","Code":1062,"Message":"Request does not contain a valid PUID."}
can you guys help me retrieving the user info?
EDIT:
solved the problem by removing the =AuthToken from the authorization and it worked!
Thanks,
Joe
Yes!
made it work after hours trying lots of differents samples from ms ¬¬
the problem was the Authorization: WRAP access_token=AuthToken=
just removed the AuthToken= and it worked!
so its now like this:
'Authorization: WRAP access_token="'.$wrapper->getReturnedParameter('wrap_access_token').'"'