As suggested on stackoverflow, I make sure to log in to https://developer.paypal.com, to set cookies for sandbox development before attempting my SetExpressCheckout flows.
I get a successful response from my SetExpressCheckout call, with a reply such as:
TOKEN=EC%2d2D3179619P0352202&TIMESTAMP=2014%2d08%2d08T01%3a58%3a29Z&CORRELATIONID=ca8756c977f0&ACK=Success&VERSION=116&BUILD=12301660
My problem comes when trying to redirect to PayPal with the _express-checkout command:
I extract the TOKEN value, and pass that in an HTTP form, with GET and POST variations shown below. I'm using Perl, but the forms are just plain HTML, and the forms below are taken directly from viewing the page source that is generated by my Perl CGI script.
form using GET:
<form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="GET">
<input type="hidden" name="cmd" value="_express-checkout">
<input type="hidden" name="token" value="EC%2d1BH04005UH441943R">
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_buynow_SM.gif" border="0" alt="PayPal - The safer, easier way to pay online!">
</form>
form URL: https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC%252d1BH04005UH441943R&x=61&y=11
lands on: https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_flow&SESSION=S4XbHMPLePuv_A93vhHvqIo4GEYOpsQCYkn6iiIE6AeRfMEkXHzSPWYeH3G&dispatch=50a222a57771920b6a3d7b606239e4d529b525e0b7e69bf0224adecfb0124e9b61f737ba21b08198a0586321b47f5ae7b54ee269d9200b8b
( PayPal page with "This transaction is invalid. Please return to the recipient's website to complete your transaction using their regular checkout flow." )
form using POST:
<form action=https://www.sandbox.paypal.com/cgi-bin/webscr METHOD='POST'>
<input type=hidden name='cmd' value='_express-checkout'>
<input type=hidden name='token' value=EC%2d9MK58577ER8913409>
<input type=image src=https://www.paypalobjects.com/en_US/i/btn/btn_buynow_SM.gif border=0 alt='PayPal - The safer, easier way to pay online!'>
</form>
form URL: https://www.sandbox.paypal.com/cgi-bin/webscr
lands on: https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_flow&SESSION=MQjOoKQ1FNeHGrVOsukD0Ln8K8LvfvfrejsDm9XZq3JeLThBanMZ2vC1Wtm&dispatch=50a222a57771920b6a3d7b606239e4d529b525e0b7e69bf0224adecfb0124e9b61f737ba21b08198a0586321b47f5ae7b54ee269d9200b8b
( PayPal page with "This transaction is invalid. Please return to the recipient's website to complete your transaction using their regular checkout flow." )
Curiously, if I manually enter the URL that would have been the 'action=' URL of my form using method=GET, it all works:
Manual cut-n-paste of form URL: https://www.sandbox.paypal.com/cgi-bin/webscr&cmd=_express-checkout&token=EC%2d00D71751FM635411H (with or w/o appending &x=nn&y=nn)
lands on: https://www.sandbox.paypal.com/cgi-bin/webscr&cmd=_express-checkout&token=EC%2d00D71751FM635411H
( Sandbox test store, showing order summary and buyer PayPal account login prompts, as expected )
It seems to me there is some issue with PayPal's session caching, since my form URLs get transformed to ones with parms "_cmd=flow&SESSION={long session ID}, but I clear (Safari) browser cookies before logging in to developer.paypal.com.
I get similar behavior on a different computer, using Firefox and IE browsers.
PayPal won't accept your token because you send it back as percent-encoded twice.
The SetExpressCheckout response is a string that contains a series of parameter names and values. This string is percent-encoded, meaning that you need to decode it to extract the actual values.
Most importantly, you are interested in the TOKEN=EC%2d2D3179619P0352202
part, where the %2d
represents the character -
.
When you re-inject the string directly to a form input as shown in your question, the %2d
represents nothing but the sequence of characters %
2
d
. Moreover, when sent to PayPal as a GET request, the sequence will be percent-encoded itself, with the percent sign encoded to %25
, resulting in the sequence %
2
5
2
d
that you observed. So the token gets lost in translation.
What you need to input is the decoded version of the token:
<input type="hidden" name="token" value="EC-1BH04005UH441943R">
In Perl, the decoding can be achieved using, for example, CPAN's URI::Escape module.