In addition to the client-side callback, you can configure a URL that the payment system should send a server-to-server callback to, which you can use to securely validate successful purchases.
To enable this feature, you need to enter a URL in the Payments tab under the Publishing Network setup for your game in the Games Control Panel.
The callback will be made as an HTTP POST to the URL you’ve configured.
In general, all parameters that you supplied in the call to open the payment dialog will be returned in the callback. In addition, the callback will contain a few more parameters that are necessary to process and verify the contents of it.
|name||The name you supplied.|
|description||The description you supplied.|
|icon||The icon you supplied.|
|currency||The currency you supplied.|
|amount||The amount you supplied.|
|transactionid||The transaction ID you supplied.|
|gameuserid||The user ID of the user making the purchase. This is the same value as you can decode from the user token on the canvas page.|
|paymentresult||The result of the payment, either 'success' or 'failure'|
|paymenttransactionid||The transaction ID that was generated by the Publishing Network Payment system.|
|paymenterrormessage||An error message describing why the payment failed or was declined, if any.|
|version||The version of the authentication scheme, currently 'V1_HMACSHA256'.|
|timestamp||The unix timestamp of when the callback was made.|
|auth||The authentication string that can be used to verify the callback.|
Any additional parameters that you supplied in the original call to open the payment dialog, will be sent back in the server callback. As in the example on the payment documentation page, if you add the parameter 'foo' with the value 'bar', those values will be added to the server callback.
All parameters in the server callback are part of the auth signature, which protects against a user spoofing parts of the payment dialog call.
Validating the callback
To make sure that the callback is legit and coming from PlayerIO servers, you need to do the following:
- Verify that the transaction ID was created by your system, and that you haven’t processed this transaction before, if your transaction IDs are unique.
- Verify that the currency and amount matches the item bought. A user could intercept the client-side code and input his own amount to try to purchase something for a lower price.
- Verify that the timestamp is fresh. If the timestamp is old, it might be someone trying to replay an intercepted callback.
- Validate the auth signature using your unique Game Secret.
Validating the auth signature
The auth signature is calculated using the HMACSHA256 algorithm, where the key is the same Game Secret that’s used for validating the user token, that you can find on the Canvas Setup page. The message is a string consisting of all key-value pairs in the POST, except ‘auth’, in alphabetical order, concatenated one after the other. The hash result is then Base64URLEncoded.
In pseudocode, the auth can be validated like this:
For example, if the POST contains the following key-value-pairs:
name: 150 Bucks
The message used to calculate the signature would be:
If your game secret is:
The resulting auth would be:
Which matches what was sent in the original server callback, thereby validating it.
Responding to the callback
When you receive the callback and have processed it, your script should return a string starting with “ok” and the HTTP status code 200.
Any other response will cause the payment system to retry the callback up to 20 times, over a period of three days. This ensures that callbacks will be reliably delivered in case your receiving script or webservers have any issues.
The Games Control Panel lists all your latest callback attempts, so that you can see why you’re receiving retries, if any.
Refunds and Chargebacks
If a payment is either refunded or if the user performed a chargeback through their bank, you will receive a corresponding callback to your system.
In case of a refund, you will receive a callback that is identical to the one from the original payment, except the 'paymentresult' parameter will contain the value 'refunded'. You should validate the callback as usual, and you can then use the transaction ID and user ID to then take an appropriate action, for example removing the item bought from the user's inventory.
In case of a chargeback, you will receive a callback that is identical to the one from the original payment, except the 'paymentresult' parameter will contain the value 'charged back'. You should validate the callback as usual, and you can then use the transaction ID and user ID to then take an appropriate action, for example prohibiting that user from making any further in-game payments.