Facebook issues two types of HTTP POST requests to the URL specified at Payments Callback URL. To configure the app's Payments Callback URL, visit this documentation. The two types of app server requests compliment the Pay Dialog by:
In both cases, the developer will need to parse the signed request to authenticate and process Facebook's requests.
In addition to standard signed_request fields, the developer is required to process an additional field named credits whose value is an array. The contents of the array will depend on the Facebook request type.
Not all Pay Dialogs result in both types of app sever requests. The following table articulates the relationship.
Pay Dialog action value | Facebook sendspayments_get_items request? | Facebook sendspayments_status_update request? |
|---|---|---|
buy_item | Yes. When a user buys an item from the developer, Facebook needs the developer to provide the order information. As a result, Facebook sends a payments_get_items request to the developer's Credits Callback URL containing the Pay Dialog's order_info value. The developer's response must contain the order information because this information is then displayed in the Pay Dialog. Details on this request can be found here. | Yes. After a user places an order and Facebook reserves the user's funds to purchase this order, Facebook sends a payments_status_update request to the developer's Credits Callback URL. Assuming the developer fulfills the order based on the order_details value, the developer should settle the order by responding so that Facebook can transfer the funds from the user to the developer. Details on this request can be found here. |
earn_currency | No. Facebook does not send a payments_get_items request because the order information is calculated based on the Pay Dialog's product value which is an app's currency OG object URL. | Yes. After a user completes an offer, an item order for the app's currency is placed, and Facebook reserves the user's funds to purchase this order. Then Facebook sends a payments_status_update request to the developer's Credits Callback URL to inform the developer that the user has placed an order. Assuming the developer fulfills the order based on the modified value, the developer should settle the order by responding so that Facebook can transfer the funds from the user to the developer. Details on this request can be found here. |
buy_credits | No. Since the user purchases credits and Facebook understands credits' orders, Facebook does not send a payments_get_items request to the developer's Credits Callback URL. | No. Since the user is purchasing credits from Facebook and Facebook is responsible for fulfilling orders for credits, Facebook does not send a payments_status_update to the developer's Credits Callback URL indicating that orders for credits have been placed. |
A PHP example can be found here.
To open an item order in the Pay Dialog, Facebook issues an app server request for the item information. Facebook uses the developers response to this request to populate the Pay Dialog.
Note that Facebook considers app currencies orders (e.g. Fred's App's Cash) as item orders.
To identify the type of request, inspect the POST parameter method for the value payments_get_items.
An example POST request body,
signed_request=rb6-VQP3uFb8y3rAgOuVR9SiOMUaWqk1NJGt...&
buyer=409697&
receiver=409697&
order_id=9006597900959&
order_info={"item_id":"1a"}&
method=payments_get_items
After parsing the POST parameter signed_request value, the credits field contains an array with the following fields.
| Name | Type | Value |
|---|---|---|
buyer | Integer | The UID of the buyer. |
receiver | Integer | The UID of the order recipient. |
order_id | Integer | 64-bit Facebook order id. If the app server is not configured for 64-bit integers, the value can be cast into a string. |
order_info | String | The order information passed when the FB.ui is invoked |
An example parsed and JSON decoded signed_request,
Array(
[algorithm] => HMAC-SHA256
[credits] => Array(
[buyer] => 409697
[receiver] => 409697
[order_id] => 9006597900959
[order_info] => {"item_id":"1a"}
)
[expires] => 1325210400
[issued_at] => 1325203762
[oauth_token] => AAABhWGUwIE8BABlFo...
[user] => Array(
[country] => us
[locale] => en_US
[age] => Array(
[min] => 21
)
)
[user_id] => 409697
)
Developers should use the order_info passed from FB.ui and parsed from the signed_request value to determine the actual item information.
Since invoking FB.ui occurs on the client, anyone with access to the client can mutate order_info.
As a result, Facebook issues this request to the developer's app server so that the developer can validate and utilize order_info to determine the actual item information.
After validating the order_info and using it to lookup the actual item information, the developer should respond with the following information.
| Name | Type | Description | Required |
|---|---|---|---|
method | String | The value payments_get_items. | Yes |
title | String | The name of the product. String length must be <= 50 characters. | Yes |
description | String | A description of the product. String length must be <= 175 characters. | Yes |
image_url | String | The URL for the image to display to the user. | Yes |
product_url | String | A permalink to the product's URL. | Yes |
price | Integer | The product cost based in credits. All product costs must be based in credits. Integer value must be > 0. | Yes |
item_id | String | A developer specific id for the product. Not used by Facebook. | No |
data | array | JSON encoded array containing the order information. | No |
The structure of the response is a JSON string whose contents contain an object with two fields.
The content field contains all of the above attributes except method and is represented as the 0th property of an object.
The method field contains the string payments_get_items.
An example developer JSON string response,
{
"content":[
{
"title":"BFF Locket",
"description":"Best friend locket",
"price":1,
"image_url":"http:\/\/www.facebook.com\/images\/gifts\/21.png"
}
],
"method":"payments_get_items"
}
After receiving the developer's response containing the item information, Facebook opens the Pay Dialog displaying the provided item information.
Facebook issues order status update requests under the following circumstances:
Note: Facebook sometimes issues a second payments_status_update request with the settled status. Developers should ignore this request. Facebook will be removing this second request on March 1, 2012 so developers should not depend on it.
Facebook issues an order status update request after the user confirms the item order in from the Pay Dialog.
This notifies the app that a user's order is ready to be processed.
To identify the type of request, inspect the POST parameter method for the value payments_status_update.
An example POST request body,
signed_request=IdUotyZ7b-bT1gCJx8ClnCIPx742ldxUtlvZ...&
order_details={"order_id":9007076736544,"buyer":409697,
"app":107032282669135,"receiver":409697,"amount":1,
"time_placed":1329243276,"update_time":1329243277,
"data":"","items":[{"item_id":"0","title":"100 FredCoins",
"description":"Spend FredCoins for all things in FredLand.",
"image_url":"http:\/\/www.inexpensivegold.com\/wp-content\/uploads\/2009\/12\/20-liberty-double-eagle.jpg",
"product_url":"","price":1,"data":""}],
"status":"placed"}&
status=placed&
order_id=9007076736544&
method=payments_status_update
After parsing the POST parameter signed_request value, the credits field contains an array with the following fields.
| Name | Type | Value |
|---|---|---|
order_details | JSON string | Contains the developer's payments_get_items response information. See below for an example. |
status | String | The value placed. This indicates that the user has placed the order and that Facebook has reserved the funds from the user for this order. |
order_id | Integer | 64-bit Facebook order id. Parsing the signed_request can garble this value. Use the order_id in the above order_details field. |
An example parsed and JSON decoded signed_request,
Array(
[algorithm] => HMAC-SHA256
[credits] => Array(
[order_details] => {"order_id":9007076736544,"buyer":409697,"app":107032282669135,"receiver":409697,"amount":1,"time_placed":1329243276,"update_time":1329243277,"data":"","items":[{"item_id":"0","title":"100 FredCoins","description":"Spend FredCoins for all things in FredLand.","image_url":"http:\/\/www.inexpensivegold.com\/wp-content\/uploads\/2009\/12\/20-liberty-double-eagle.jpg","product_url":"","price":1,"data":""}],"status":"placed"}
[status] => placed
[order_id] => 9007076736544
)
[expires] => 1329249600
[issued_at] => 1329243278
[oauth_token] => AAABhWGUwIE8BALBqO...
[user] => Array(
[country] => us
[locale] => en_US
[age] => Array(
[min] => 21
)
)
[user_id] => 409697
)
JSON decoding the above example order_details value yields:
Array(
[order_id] => 9007076736544
[buyer] => 409697
[app] => 107032282669135
[receiver] => 409697
[amount] => 1
[time_placed] => 1329243276
[update_time] => 1329243277
[data] =>
[items] => Array(
[0] => Array(
[item_id] => 0
[title] => 100 FredCoins
[description] => Spend FredCoins for all things in FredLand.
[image_url] => http://www.inexpensivegold.com/wp-content/uploads/2009/12/20-liberty-double-eagle.jpg
[product_url] =>
[price] => 1
[data] =>
)
)
[status] => placed
)
Developers should respond with the following information.
| Name | Type | Description | Required |
|---|---|---|---|
method | String | The value payments_status_update. | Yes |
order_id | String | The order id for the order which was placed by the user. | Yes |
status | String | The value settled or canceled. See below for details. | Yes |
The structure of the response is a JSON string whose contents contain an object with two fields.
The content field contains all of the above attributes except method and is represented as the 0th element of an array.
The method field contains the string payments_get_items.
More specifically, developers have two options:
1. Settle the placed order by:
Fulfilling the order by depositing the appropriate amount of virtual currency or item. Developers can use the order_details to determine what goods to deliver.
Responding to this payments_status_update with settled. An example developer settled JSON string response,
{
"content":{
"status":"settled",
"order_id":9006195253076
},
"method":"payments_status_update"
}
price for the order and these transactions are represented as type S in the developer payout reports.2. Or cancel the placed order by:
payments_status_update with canceled. An example developer canceled JSON string response,
{
"content":{
"status":"canceled",
"order_id":9006203669116
},
"method":"payments_status_update"
}
If the developer settles the order, Facebook will open an appropriate order confirmation dialog.
For both the settled and canceled response options, Facebook will return data to the client.
Facebook issues an order status update request after the user completes an In-app Currency Offer.
This notifies the app that a user's order is ready to be processed.
To identify the type of request, inspect the POST parameter method for the value payments_status_update.
An example POST request body,
signed_request=lqk6mXAGGhmUvsZ_jbKezG1bGq7whh7Ecmvj...&
order_details={"order_id":9007080443022,"buyer":409697,
"app":107032282669135,"receiver":409697,"amount":1,
"time_placed":1329408828,"update_time":1329408830,
"data":"","items":[{"item_id":"0","title":"3 Fred Currency",
"description":"Make it rain!",
"image_url":"URL_TO_SOME_IMAGE",
"product_url":"","price":1,
"data":"{\"modified\":{\"product\":\"URL_TO_APP_CURR_WEBPAGE\",
\"product_title\":\"Fred Currency\",\"product_amount\":3,\"credits_amount\":1}}"}],
"status":"placed"}&
status=placed&
order_id=9007080443022&
method=payments_status_update
After parsing the POST parameter signed_request value, the credits field contains an array with the following fields.
| Name | Type | Value |
|---|---|---|
order_details | JSON string | Contains the developer's payments_get_items response information. See below for an example. |
status | String | The value placed. This indicates that the user has placed the order and that Facebook has reserved the funds from the user for this order. |
order_id | Integer | 64-bit Facebook order id. Parsing the signed_request can garble this value. Use the order_id in the above order_details field. |
An example parsed and JSON decoded signed_request,
Array(
[algorithm] => HMAC-SHA256
[credits] => Array(
[order_details] => {"order_id":9007080443022,"buyer":409697,"app":107032282669135,"receiver":409697,"amount":1,"time_placed":1329408828,"update_time":1329408830,"data":"","items":[{"item_id":"0","title":"3 Fred Currency","description":"Make it rain!","image_url":"URL_TO_SOME_IMAGE","product_url":"","price":1,"data":"{\"modified\":{\"product\":\"URL_TO_APP_CURR_WEBPAGE\",\"product_title\":\"Fred Currency\",\"product_amount\":3,\"credits_amount\":1}}"}],"status":"placed"}
[status] => placed
[order_id] => 534023310
)
[expires] => 1329415200
[issued_at] => 1329408831
[oauth_token] => AAABhWGUwIE8BAAB6g...
[user] => Array(
[country] => us
[locale] => en_US
[age] => Array(
[min] => 21
)
)
[user_id] => 409697
)
JSON decoding the above example order_details value yields:
Array(
[order_id] => 9007080443022
[buyer] => 409697
[app] => 107032282669135
[receiver] => 409697
[amount] => 1
[time_placed] => 1329408828
[update_time] => 1329408830
[data] =>
[items] => Array(
[0] => Array(
[item_id] => 0
[title] => 3 Fred Currency
[description] => Make it rain!
[image_url] => URL_TO_SOME_IMAGE
[product_url] =>
[price] => 1
[data] => {"modified":{"product":"URL_TO_APP_CURR_WEBPAGE","product_title":"Fred Currency","product_amount":3,"credits_amount":1}}
)
)
[status] => placed
)
Unlike payments_status_update for placed item orders which have a preceding payments_get_items for the developer's item information, payments_status_update for earned app currency does not have a preceding payments_get_items.
As a result, the developer must JSON decode the order_details' items' 0th element's data field's value to understand the contents of the order.
JSON decoding the data value yields an array with the modified element.
The modified element contains an array following information:
product: A URL to app's currency object instance. The user is purchasing this app currency.
product_title: The title of app's currency.
product_amount: The integer amount of app currency to deposit into the user’s balance.
credits_amount: The integer credits amount which will be paid to the developer for fulfilling and settling the order.
JSON decoding the above example data value yields:
Array(
[modified] => Array(
[product] => URL_TO_APP_CURR_WEBPAGE
[product_title] => Fred Currency
[product_amount] => 3
[credits_amount] => 1
)
)
Developers should respond with the following information.
| Name | Type | Description | Required |
|---|---|---|---|
method | String | The value payments_status_update. | Yes |
order_id | String | The order id for the order which was placed by the user. | Yes |
status | String | The value settled or canceled. See below for details. | Yes |
The structure of the response is a JSON string whose contents contain an object with two fields.
The content field contains all of the above attributes except method and is represented as the 0th element of an array.
The method field contains the string payments_get_items.
Developers have two options:
1. Settle the placed order by:
Depositing the product_amount of the product into the user’s app currency balance.
Responding to this payments_status_update with settled. An example developer settled JSON string response,
{
"content":{
"status":"settled",
"order_id":9006195253076
},
"method":"payments_status_update"
}
The developer is paid the credits_amount for the order and these transactions are represented as type S in the developer payout reports.
Facebook then makes a confirmation request to the callback, passing in the same data as in the previous (placed) request, except that the status will be settled. To confirm that you've fulfilled the order, respond with the precise same content that you returned for the previous (placed) call.
2. Or cancel the placed order by:
code and the value 131. An example developer canceled JSON string response,
{
"content":{
"status":"canceled",
"code":131,
"order_id":9006203669116
},
"method":"payments_status_update"
}
credits_amount for the canceled order.For both the settled and canceled response options, Facebook will return data to the client.
It’s possible for a user to complete multiple offers in a single Facebook offerwall dialog. Facebook only returns the last completed order_id to the client.
Facebook issues an order status update request after the user disputes an item order. An illustration describing the user dispute experience can be found here.
This notifies the app that a user's disputed item order is ready to be processed.
To identify the type of request, inspect the POST parameter method for the value payments_status_update.
An example POST request body,
signed_request=qxvRyt82FDTSipYTu0CEnYp4aNDDGAci4jmQ...&
order_details={"order_id":9007249182704,"buyer":409697,
"app":107032282669135,"receiver":409697,"amount":1,
"time_placed":1330641001,"update_time":1330646619,
"data":"","items":[{"item_id":"0","title":"100 FredCoins",
"description":"Spend FredCoins for all things in FredLand.",
"image_url":"http:\/\/www.inexpensivegold.com\/wp-content\/uploads\/2009\/12\/20-liberty-double-eagle.jpg",
"product_url":"","price":1,"data":""}],
"status":"disputed"}&
status=disputed&
order_id=9007249182704&
method=payments_status_update
After parsing the POST parameter signed_request value, the credits field contains an array with the following fields.
| Name | Type | Value |
|---|---|---|
order_details | JSON string | Contains the developer's payments_get_items response information. See below for an example. |
status | String | The value disputed. This indicates that the user has disputed the order and that Facebook has reserved the funds from the user for this order. |
order_id | Integer | 64-bit Facebook order id. Parsing the signed_request can garble this value. Use the order_id in the above order_details field. |
An example parsed and JSON decoded signed_request,
Array(
[algorithm] => HMAC-SHA256
[credits] => Array(
[order_details] => {"order_id":9007249182704,"buyer":409697,"app":107032282669135,"receiver":409697,"amount":1,"time_placed":1330641001,"update_time":1330646619,"data":"","items":[{"item_id":"0","title":"100 FredCoins","description":"Spend FredCoins for all things in FredLand.","image_url":"http:\/\/www.inexpensivegold.com\/wp-content\/uploads\/2009\/12\/20-liberty-double-eagle.jpg","product_url":"","price":1,"data":""}],"status":"disputed"}
[status] => disputed
[order_id] => 9007249182704
)
[expires] => 1330653600
[issued_at] => 1330646620
[oauth_token] => AAABhWGUwIE8BAH8cd...
[user] => Array(
[country] => us
[locale] => en_US
[age] => Array(
[min] => 21
)
)
[user_id] => 409697
)
JSON decoding the above example order_details value yields:
Array(
[order_id] => 9007249182704
[buyer] => 409697
[app] => 107032282669135
[receiver] => 409697
[amount] => 1
[time_placed] => 1330641001
[update_time] => 1330646619
[data] =>
[items] => Array(
[0] => Array(
[item_id] => 0
[title] => 100 FredCoins
[description] => Spend FredCoins for all things in FredLand.
[image_url] => http://www.inexpensivegold.com/wp-content/uploads/2009/12/20-liberty-double-eagle.jpg
[product_url] =>
[price] => 1
[data] =>
)
)
[status] => disputed
)
Developers cannot synchronously respond to payments_status_update requests with disputed status.
Developers must investigate the user's item order dispute and respond asynchronously using the Graph API.
After investigating a user's dispute, developers have two options:
1. Settle the disputed order after the developer has satisfactorily resolved the user's dispute.
To update the order status, developers should issue a POST request to the Graph API order id payments endpoint [order_id]/payments with the following parameters.
| Name | Type | Value |
|---|---|---|
status | String | settled. |
message | String | The reason for settling a user's disputed order. |
accees_token | String | An app access token. |
For example,
curl -F 'status=settled' -F 'message=the reason for settling a disputed order' 'https://graph.facebook.com/[order_id]?access_token=[app_access_token]'
These transactions are represented as type S in the developer payout reports.
2. Or refund the disputed order. The user cannot be made whole so refund the credits spent.
To update the order status, developers should issue a POST request to the Graph API order id payments endpoint [order_id]/payments with the following parameters.
| Name | Type | Value |
|---|---|---|
status | String | refunded. |
message | String | The reason for refunding a user's disputed order. |
accees_token | String | An app access token. |
For example,
curl -F 'status=refunded' -F 'message=the reason for refunding a disputed order' 'https://graph.facebook.com/[order_id]?access_token=[app_access_token]'
These transactions are represented as type R in the developer payout reports.
Facebook occasionally refunds item orders. The disputes and chargebacks documentation describes the circumstances of Facebook initiated refunds.
This request notifies the developer that Facebook has refunded a user's item order and is purely for notification purposes. No developer response is required.
To identify the type of request, inspect the POST parameter method for the value payments_status_update.
An example POST request body,
signed_request=JKGO2cquBoKG-ZPt_P5EEqrI8wUGgPmZUdcM...&
order_details={"order_id":9007142886185,"buyer":409697,
"app":107032282669135,"receiver":409697,"amount":1,
"time_placed":1329866240,"update_time":1329868837,
"data":"","items":[{"item_id":"0","title":"100 FredCoins",
"description":"Spend FredCoins for all things in FredLand.",
"image_url":"http:\/\/www.inexpensivegold.com\/wp-content\/uploads\/2009\/12\/20-liberty-double-eagle.jpg",
"product_url":"","price":1,"data":""}],
"status":"refunded"}&
status=refunded&
order_id=9007142886185&
method=payments_status_update
After parsing the POST parameter signed_request value, the credits field contains an array with the following fields.
| Name | Type | Value |
|---|---|---|
order_details | JSON string | Contains the developer's payments_get_items response information. See below for an example. |
status | String | The value refunded. This indicates that the order has been refunded. |
order_id | Integer | 64-bit Facebook order id. Parsing the signed_request can garble this value. Use the order_id in the above order_details field. |
An example parsed and JSON decoded signed_request,
Array(
[algorithm] => HMAC-SHA256
[credits] => Array(
[order_details] => {"order_id":9007142886185,"buyer":409697,"app":107032282669135,"receiver":409697,"amount":1,"time_placed":1329866240,"update_time":1329868837,"data":"","items":[{"item_id":"0","title":"100 FredCoins","description":"Spend FredCoins for all things in FredLand.","image_url":"http:\/\/www.inexpensivegold.com\/wp-content\/uploads\/2009\/12\/20-liberty-double-eagle.jpg","product_url":"","price":1,"data":""}],"status":"refunded"}
[status] => refunded
[order_id] => 9007142886185
)
[expires] => 1329876000
[issued_at] => 1329868837
[oauth_token] => AAABhWGUwIE8BAKGqI...
[user] => Array(
[country] => us
[locale] => en_US
[age] => Array(
[min] => 21
)
)
[user_id] => 409697
)
JSON decoding the above example order_details value yields:
Array(
[order_id] => 9007142886185
[buyer] => 409697
[app] => 107032282669135
[receiver] => 409697
[amount] => 1
[time_placed] => 1329866240
[update_time] => 1329868837
[data] =>
[items] => Array(
[0] => Array(
[item_id] => 0
[title] => 100 FredCoins
[description] => Spend FredCoins for all things in FredLand.
[image_url] => http://www.inexpensivegold.com/wp-content/uploads/2009/12/20-liberty-double-eagle.jpg
[product_url] =>
[price] => 1
[data] =>
)
)
[status] => refunded
)
A payments_status_update with refunded status is purely for developer notification purposes. No developer response is required.
Developers may use these notifications to inform their internal representation of the order status.
<?php
$app_secret = 'APP_SECRET';
// Validate request is from Facebook and parse contents for use.
$request = parse_signed_request($_POST['signed_request'], $app_secret);
// Get request type.
// Two types:
// 1. payments_get_items.
// 2. payments_status_update.
$request_type = $_POST['method'];
// Setup response.
$response = '';
if ($request_type == 'payments_get_items') {
// Get order info from Pay Dialog's order_info.
// Assumes order_info is a JSON encoded string.
$order_info = json_decode($request['credits']['order_info'], true);
// Get item id.
$item_id = $order_info['item_id'];
// Simulutates item lookup based on Pay Dialog's order_info.
if ($item_id == '1a') {
$item = array(
'title' => '100 some game cash',
'description' => 'Spend cash in some game.',
// Price must be denominated in credits.
'price' => 1,
'image_url' => 'http://some_image_url/coin.jpg',
);
// Construct response.
$response = array(
'content' => array(
0 => $item,
),
'method' => $request_type,
);
// Response must be JSON encoded.
$response = json_encode($response);
}
} else if ($request_type == "payments_status_update") {
// Get order details.
$order_details = json_decode($request['credits']['order_details'], true);
// Determine if this is an earned currency order.
$item_data = json_decode($order_details['items'][0]['data'], true);
$earned_currency_order = (isset($item_data['modified'])) ?
$item_data['modified'] : null;
// Get order status.
$current_order_status = $order_details['status'];
if ($current_order_status == 'placed') {
// Fulfill order based on $order_details unless...
if ($earned_currency_order) {
// Fulfill order based on the information below...
// URL to the application's currency webpage.
$product = $earned_currency_order['product'];
// Title of the application currency webpage.
$product_title = $earned_currency_order['product_title'];
// Amount of application currency to deposit.
$product_amount = $earned_currency_order['product_amount'];
// If the order is settled, the developer will receive this
// amount of credits as payment.
$credits_amount = $earned_currency_order['credits_amount'];
}
$next_order_status = 'settled';
// Construct response.
$response = array(
'content' => array(
'status' => $next_order_status,
'order_id' => $order_details['order_id'],
),
'method' => $request_type,
);
// Response must be JSON encoded.
$response = json_encode($response);
} else if ($current_order_status == 'disputed') {
// 1. Track disputed item orders.
// 2. Investigate user's dispute and resolve by settling or refunding the order.
// 3. Update the order status asychronously using Graph API.
} else if ($current_order_status == 'refunded') {
// Track refunded item orders initiated by Facebook. No need to respond.
} else if ($current_order_status == 'settled') {
// Verify that the order ID corresponds to a purchase you've fulfilled, then…
// Get order details.
$order_details = json_decode($request['credits']['order_details'], true);
// Construct response.
$response = array(
'content' => array(
'status' => 'settled',
'order_id' => $order_details['order_id'],
),
'method' => $request_type,
);
// Response must be JSON encoded.
$response = json_encode($response);
} else {
// Track other order statuses.
}
}
// Send response.
echo $response;
// These methods are documented here:
// https://developers.facebook.com/docs/authentication/signed_request/
function parse_signed_request($signed_request, $secret) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
// decode the data
$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');
return null;
}
// check sig
$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
error_log('Bad Signed JSON signature!');
return null;
}
return $data;
}
function base64_url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}