Skip to main content

Introduction to entitlement revocation

Last updated on April 17, 2024
info

Extend is in Open Beta for AGS Premium Clients! This means that the Extend add-on is available for you to try in your development environment. You can submit your feedback via our Extend Open Beta feedback form.

Overview

AccelByte Gaming Services (AGS) has the capability to provide custom logic for handling the revocation of player assets with Extend. In this guide, we will present the contract of the customization with example code on how to implement a revoke function that will send the necessary information to identify the user, the object, and the quantity to be revoked.

There's only one function on the contract, seen in the snippet below which is the unary function Revoke:

service Revocation {
/**
Revoke
Currently, only Third-Party DLC Refund and Refund Order will trigger this grpc revocation.
*/
rpc Revoke(RevokeRequest) returns (RevokeResponse);
}

Revoke

Revoke allows for the handling of revocation requests triggered by specific events within a gaming or virtual economy system. It is used for implementing the logic to manage entitlements and ensures the proper handling of refunds or revocation orders.

In this example, we'll generate some custom responses for the three types of entries that are currently supported; ITEM, ENTITLEMENT, and CURRENCY.

Code Example:

The Revoke method will run the correct function based on the revokeEntryType passed in.

async def Revoke(self, request: RevokeRequest, context):
self.log_payload(f'{self.Revoke.__name__} request: %s', request)
response : RevokeResponse
try:
namespace = request.namespace
userId = request.userId
quantity = request.quantity
revoke_entry_type = RevokeEntryType[request.revokeEntryType.upper()]
revocation = Revocations().get_revocation(revoke_entry_type)
response = revocation.revoke(namespace, userId, quantity, request)
except Exception as e:
response = RevokeResponse(
reason = f"Revocation method {str(e)} not supported",
status = RevocationStatus.FAIL.name,
)
self.log_payload(f'{self.Revoke.__name__} response: %s', response)
return response

When the ITEM entry type is passed in:

class ItemRevocation(Revocation):
def __init__(self) -> None:
self.custom_revocation = dict()
super().__init__()

def revoke(self, namespace, userId, quantity, request):

item = request.item
self.custom_revocation["namespace"] = namespace
self.custom_revocation["userId"] = userId
self.custom_revocation["quantity"] = str(quantity)
self.custom_revocation["sku"] = item.itemSku
self.custom_revocation["itemType"] = item.itemType
self.custom_revocation["useCount"] = str(item.useCount)
self.custom_revocation["entitlementType"] = item.entitlementType
return RevokeResponse(
customRevocation = self.custom_revocation,
status = RevocationStatus.SUCCESS.name,
)

When CURRENCY entry is passed in:

class CurrencyRevocation(Revocation):

def __init__(self) -> None:
self.custom_revocation = dict()
super().__init__()

def revoke(self, namespace, userId, quantity, request):
currency = request.currency
self.custom_revocation["namespace"] = namespace
self.custom_revocation["userId"] = userId
self.custom_revocation["quantity"] = str(quantity)
self.custom_revocation["currencyNamespace"] = currency.namespace
self.custom_revocation["currencyCode"] = currency.currencyCode
self.custom_revocation["balanceOrigin"] = currency.balanceOrigin
return RevokeResponse(
customRevocation = self.custom_revocation,
status = RevocationStatus.SUCCESS.name,
)

When the ENTITLEMENT entry is passed in:

class EntitlementRevocation(Revocation):
def __init__(self) -> None:
self.custom_revocation = dict()
super().__init__()

def revoke(self, namespace, userId, quantity, request):

entitlement = request.entitlement
self.custom_revocation["namespace"] = namespace
self.custom_revocation["userId"] = userId
self.custom_revocation["quantity"] = str(quantity)
self.custom_revocation["entitlementId"] = entitlement.entitlementId
self.custom_revocation["itemId"] = entitlement.itemId
self.custom_revocation["sku"] = entitlement.sku
return RevokeResponse(
customRevocation = self.custom_revocation,
status = RevocationStatus.SUCCESS.name,
)

On this page