Facebook Sorry There Was an Issue With Processing Your Order Please Try Again Later
I am answering my own question to share the complete source code needed to sell consumable virtual goods via Facebook Payments Lite, based on Alexey Mukhin's helpful reply -
JavaScript code in your Facebook Canvas app (assign to a button-ONCLICK):
function buyItemLite() { var payDialog = { method: "pay", activity: "purchaseiap", product_id: "test1" }; FB.ui(payDialog, function(payResponse) { FB.getLoginStatus(function(loginResponse) { if (loginResponse.condition === "connected") { $.post("/payment-low-cal.php", { signed_request: payResponse.signed_request, access_token: loginResponse.authResponse.accessToken }) .washed(part(consumeResponse) { location.reload(); }); } }); }); }
PHP lawmaking in the payment-lite.php script hosted at your web server:
const APP_ID = 'supervene upon by your app id'; const APP_SECRET = 'supercede past your app secret'; const SIGNED_REQUEST = 'signed_request'; const STATUS = 'condition'; const COMPLETED = 'completed'; const PRODUCT_ID = 'product_id'; const PURCHASE_TOKEN = 'purchase_token'; const ACCESS_TOKEN = 'access_token'; const CONSUME_URL = 'https://graph.facebook.com/%d/consume'; $request = parse_signed_request($_REQUEST[SIGNED_REQUEST], APP_SECRET); error_log('pay dialog asking: ' . print_r($asking, Truthful)); if ($asking[Status] === COMPLETED && $request[PRODUCT_ID] === 'test1') { # perform POST asking to consume the purchase_token $url = sprintf(CONSUME_URL, $request[PURCHASE_TOKEN]); $fields = array(ACCESS_TOKEN => $_REQUEST[ACCESS_TOKEN]); $client = curl_init($url); curl_setopt($client, CURLOPT_RETURNTRANSFER, true); curl_setopt($customer, CURLOPT_POSTFIELDS, $fields); $response = curl_exec($client); curl_close($customer); error_log('consume response: ' . print_r($response, TRUE)); # TODO give the player the newly purchased consumable "test1" product } function parse_signed_request($signed_request, $secret) { list($encoded_sig, $payload) = explode('.', $signed_request, 2); $sig = base64_url_decode($encoded_sig); $data = json_decode(base64_url_decode($payload), TRUE); if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') { error_log('Unknown algorithm. Expected HMAC-SHA256'); render NULL; } $expected_sig = hash_hmac('sha256', $payload, $secret, $raw = TRUE); if ($sig !== $expected_sig) { // or amend use hash_equals error_log('Bad Signed JSON signature!'); return NULL; } render $data; } role base64_url_decode($input) { return base64_decode(strtr($input, '-_', '+/')); }
NOTE: If you happen to take a recent PHP version, then better employ hash_equals in the above code, to mitigate timing attacks.
Exercise non forget to enable Payments Lite in the Facebook Dashboard of your app and as well add a "test1" product at that place:
If y'all follow the above instructions yous will be able to purchase the "test1" item multiple times and the output you will go far the PHP logs volition look like:
pay dialog request: Assortment ( [algorithm] => HMAC-SHA256 [corporeality] => 0.01 [app_id] => 376218039240910 [currency] => EUR [issued_at] => 1501674845 [payment_id] => 1041009052696057 [product_id] => test1 [purchase_time] => 1501674843 [purchase_token] => 499658830375336 [quantity] => 1 [status] => completed ) eat response: {"success":true}
Finally, I will share beneath my webhook code for non-lite Facebook Payments, because that is what I actually have concluded up using (it handles chargebacks and does not need to marking items consumable after purchases) -
JavaScript code in your Facebook Sheet app (assign to a button-ONCLICK):
office buyItemFull() { var payDialog = { method: "pay", action: "purchaseitem", production: "https://myserver/test1.html" }; FB.ui(payDialog, function(data) { location.reload(); }); }
PHP code in the payment-full.php script hosted at your web server:
const APP_ID = 'replace by your app id'; const APP_SECRET = 'replace past your app secret'; const HUB_MODE = 'hub_mode'; const HUB_CHALLENGE = 'hub_challenge'; const HUB_VERIFY_TOKEN = 'hub_verify_token'; const SUBSCRIBE = 'subscribe'; const ENTRY = 'entry'; const CHANGED_FIELDS = 'changed_fields'; const ID = 'id'; const USER = 'user'; const Actions = 'actions'; const ITEMS = 'items'; const PRODUCT = 'production'; const Corporeality = 'amount'; # payment status tin can be initiated, failed, completed const Status = 'status'; const COMPLETED = 'completed'; # possible payment event types are listed beneath const Type = 'type'; const CHARGE = 'accuse'; const CHARGEBACK_REVERSAL = 'chargeback_reversal'; const REFUND = 'refund'; const CHARGEBACK = 'chargeback'; const Turn down = 'pass up'; const GRAPH = 'https://graph.facebook.com/v2.10/%d?access_token=%s|%due south&fields=user,actions,items'; const TEST1 = 'https://myserver/test1.html'; # called past Facebook Dashboard when "Examination Callback URL" push is pressed if (isset($_GET[HUB_MODE]) && $_GET[HUB_MODE] === SUBSCRIBE) { print($_GET[HUB_CHALLENGE]); exit(0); } # chosen when there is an update on a payment (Notation: better use hash_equals) $body = file_get_contents('php://input'); if ('sha1=' . hash_hmac('sha1', $body, APP_SECRET) != $_SERVER['HTTP_X_HUB_SIGNATURE']) { error_log('payment sig=' . $_SERVER['HTTP_X_HUB_SIGNATURE'] . ' does not match body=' . $trunk); exit(i); } # find the updated payment id and what has changed: deportment or disputes $update = json_decode($trunk, True); error_log('payment update=' . print_r($update, TRUE)); $entry = array_shift($update[ENTRY]); $payment_id = $entry[ID]; $changed_fields = $entry[CHANGED_FIELDS]; if (!in_array(ACTIONS, $changed_fields)) { error_log('payment actions has non inverse'); go out(0); } # fetch the updated payment details: user, actions, items $graph = sprintf(GRAPH, $payment_id, APP_ID, APP_SECRET); $payment = json_decode(file_get_contents($graph), True); error_log('payment details=' . print_r($payment, Truthful)); # find the user id who has paid $uid = $payment[USER][ID]; # detect the last action and its status and type $actions = $payment[Actions]; $action = array_pop($actions); $condition = $action[STATUS]; $blazon = $action[Type]; $price = $action[Amount]; # find which production was purchased $items = $payment[ITEMS]; $item = array_pop($items); $production = $item[Production]; error_log("payment uid=$uid status=$status blazon=$type production=$product price=$toll"); if ($status != COMPLETED) { error_log('payment status is not completed'); exit(0); } # money has been received, update the player tape in the database if ($type === Accuse || $type === CHARGEBACK_REVERSAL) { if ($product === TEST1) { # TODO give the player the purchased "test1" product } } else if ($type === REFUND || $blazon === CHARGEBACK || $type === DECLINE) { # TODO take away from the thespian the "test1" product }
Practice non forget to disable Payments Lite in the Facebook Dashboard of your app and too add together the "payment-full.php" webhook at that place:
Finally add together the "test1.html" product file at your web server:
<!DOCTYPE html><html> <head prefix= "og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# product: http://ogp.me/ns/product#"> <meta belongings="og:type" content="og:product" /> <meta property="og:title" content="Test1" /> <meta property="og:image" content="https://myserver/icon-50x50.png" /> <meta belongings="og:clarification" content="Test1" /> <meta belongings="og:url" content="https://myserver/test1.html" /> <meta property="product:price:corporeality" content="0.01"/> <meta property="production:price:currency" content="EUR"/> </caput> </html>
There are currently non many Facebook Payment examples to be discovered on the web.
And then upvote the question and the answer, if y'all have institute my source code (public domain license) useful, to assistance other developers to find it.
Source: https://stackoverflow.com/questions/45400242/payments-lite-serverless-first-purchase-works-but-the-second-always-fails
0 Response to "Facebook Sorry There Was an Issue With Processing Your Order Please Try Again Later"
Post a Comment