S2S Rewarded Callbacks
Server-to-Server (S2S) rewarded callbacks enable server-side reward verification.
NAM SDK has supported S2S rewarded callback functionality since version 8.5.0.
This guide explains how to integrate S2S rewarded callbacks.
Before You Begin
- S2S rewarded callback functionality is supported from NAM SDK 8.5.0 and later.
- S2S callback-related settings must be completed in NAM Admin.
[Step 1] NAM SDK Integration Complete
To use S2S rewarded callback functionality, you need NAM SDK 8.5.0 or later.
Please refer to Rewarded Ads Getting Started.
The following content assumes that NAM SDK integration has been completed.
[Step 2] S2S Rewarded Callback Parameter Configuration (Optional)
If you want to pass additional information during S2S rewarded callbacks, you can configure the following parameters. For detailed ad request information, please refer to the Ad Parameters page.
User Token Configuration
You can set a user token for rewarded callbacks using the setUserToken method.
- Kotlin
- Java
val adParam = AdParam.Builder()
.setAdUnitId("YOUR_AD_UNIT_ID")
// Set user token for rewarded callback
.setUserToken("your_user_token_here")
.build()
AdParam adParam = new AdParam.Builder()
.setAdUnitId("YOUR_AD_UNIT_ID")
// Set user token for rewarded callback
.setUserToken("your_user_token_here")
.build();
Adding Custom Parameters
You can add custom parameters for rewarded callbacks using the addRewardCustomParam method.
Please contact NAM administrator before using this feature.
- Kotlin
- Java
val adParam = AdParam.Builder()
.setAdUnitId("YOUR_AD_UNIT_ID")
.setUserToken("your_user_token_here")
// Add custom parameters for rewarded callback
.addRewardCustomParam("level", "5")
.addRewardCustomParam("stage", "boss_battle")
.build()
AdParam adParam = new AdParam.Builder()
.setAdUnitId("YOUR_AD_UNIT_ID")
.setUserToken("your_user_token_here")
// Add custom parameters for rewarded callback
.addRewardCustomParam("level", "5")
.addRewardCustomParam("stage", "boss_battle")
.build();
[Step 3] RewardedAdListener Configuration
The RewardedAdListener interface has been enhanced to support S2S rewarded callbacks. It has been changed to an interface with Kotlin implementation, and new callback methods have been added.
New Callback Methods
- onFailedServerRewardVerification: Reward verification has failed, and retrying is futile.
- onReceiveErrorServerRewardVerification: An error occurred during the verification process (such as timeout), and retrying may be needed according to service policy.
- onSuccessServerRewardVerification: The user is eligible to receive the reward.
- Kotlin
- Java
rewardedAdManager.setAdListener(
object : RewardedAdListener {
override fun onAdLoaded(ad: GfpRewardedAd) {
// Ad loaded successfully - ready to show ad
}
override fun onAdStarted(ad: GfpRewardedAd) {
// Ad started
}
override fun onAdClicked(ad: GfpRewardedAd) {
// Ad clicked
}
override fun onAdClosed(ad: GfpRewardedAd) {
// Ad closed
}
override fun onAdCompleted(ad: GfpRewardedAd) {
// Ad viewing completed
}
override fun onError(ad: GfpRewardedAd, error: GfpError) {
// Error occurred while loading or showing ad
}
override fun onFailedServerRewardVerification(ad: GfpRewardedAd, error: GfpError) {
// Reward verification denied by server - retrying is useless
// Inform user that reward cannot be granted
}
override fun onReceiveErrorServerRewardVerification(ad: GfpRewardedAd) {
// Error occurred during reward verification - retry may be needed according to service policy
// Ask user for retry or perform automatic retry
}
override fun onSuccessServerRewardVerification(ad: GfpRewardedAd) {
// Server reward verification successful - user can receive reward
// Grant reward to user
}
}
)
rewardedAdManager.setAdListener(new RewardedAdListener() {
@Override
public void onAdLoaded(GfpRewardedAd ad) {
// Ad loaded successfully - ready to show ad
}
@Override
public void onAdStarted(GfpRewardedAd ad) {
// Ad started
}
@Override
public void onAdClicked(GfpRewardedAd ad) {
// Ad clicked
}
@Override
public void onAdClosed(GfpRewardedAd ad) {
// Ad closed
}
@Override
public void onAdCompleted(GfpRewardedAd ad) {
// Ad viewing completed
}
@Override
public void onError(GfpRewardedAd ad, GfpError error) {
// Error occurred while loading or showing ad
}
@Override
public void onFailedServerRewardVerification(GfpRewardedAd ad, GfpError error) {
// Reward verification denied by server - retrying is useless
// Inform user that reward cannot be granted
}
@Override
public void onReceiveErrorServerRewardVerification(GfpRewardedAd ad) {
// Error occurred during reward verification - retry may be needed according to service policy
// Ask user for retry or perform automatic retry
}
@Override
public void onSuccessServerRewardVerification(GfpRewardedAd ad) {
// Server reward verification successful - user can receive reward
// Grant reward to user
}
});
[Step 4] Checking Server Verification Availability
After the ad is loaded, you can use the isUseServerVerification method to check if server-side verification is enabled for that ad.
- Kotlin
- Java
override fun onAdLoaded(ad: GfpRewardedAd) {
// Check if server verification is enabled
val isServerVerificationEnabled = rewardedAdManager.isUseServerVerification()
if (isServerVerificationEnabled) {
logTextView.append("Server-side verification is enabled.\n")
// Logic for using S2S rewarded callbacks
} else {
logTextView.append("Using client-side verification.\n")
// Logic for using existing onAdCompleted callback
}
showButton.isEnabled = true
}
@Override
public void onAdLoaded(GfpRewardedAd ad) {
// Check if server verification is enabled
boolean isServerVerificationEnabled = rewardedAdManager.isUseServerVerification();
if (isServerVerificationEnabled) {
logTextView.append("Server-side verification is enabled.\n");
// Logic for using S2S rewarded callbacks
} else {
logTextView.append("Using client-side verification.\n");
// Logic for using existing onAdCompleted callback
}
showButton.setEnabled(true);
}
[Step 5] Using Retry API
When the onReceiveErrorServerRewardVerification
callback occurs and a retry is needed, you can use the requestServerVerification()
method of GfpRewardedAdManager.
- Kotlin
- Java
override fun onReceiveErrorServerRewardVerification(ad: GfpRewardedAd) {
// Perform retry according to service policy
// Example: Retry after user confirmation
showRetryDialog { shouldRetry ->
if (shouldRetry) {
rewardedAdManager.requestServerVerification()
} else {
// Close ad
rewardedAdManager.close()
}
}
}
@Override
public void onReceiveErrorServerRewardVerification(GfpRewardedAd ad) {
// Perform retry according to service policy
// Example: Retry after user confirmation
showRetryDialog(shouldRetry -> {
if (shouldRetry) {
rewardedAdManager.requestServerVerification();
} else {
// Close ad
rewardedAdManager.close();
}
});
}
[Step 6] Using Close Ad API
When retrying is not possible or meaningless, you can close the ad using the close()
method of GfpRewardedAdManager.
- Kotlin
- Java
override fun onFailedServerRewardVerification(ad: GfpRewardedAd, error: GfpError) {
// Verification failed - retry not possible
// Inform user and close ad
showRewardFailureMessage()
rewardedAdManager.close()
}
@Override
public void onFailedServerRewardVerification(GfpRewardedAd ad, GfpError error) {
// Verification failed - retry not possible
// Inform user and close ad
showRewardFailureMessage();
rewardedAdManager.close();
}
[Optional] Implementing Dialog-based Retry Popup
If you want to implement a retry popup in the form of a dialog Activity, you can use the provided NdaRewardCallbackBroadcastReceiver
example.
Complete Implementation Example
- Kotlin
- Java
class RewardedFragment : Fragment() {
private var rewardedAdManager: GfpRewardedAdManager? = null
private lateinit var binding: FragmentRewardedBinding
private lateinit var logTextView: TextView
private lateinit var showButton: Button
private var ndaRewardCallbackBroadcastReceiver: NdaRewardCallbackBroadcastReceiver? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentRewardedBinding.inflate(inflater)
logTextView = binding.logTextView
showButton = binding.showButton.apply {
isEnabled = false
setOnClickListener {
if (rewardedAdManager?.isAdInvalidated != false) {
logTextView.append("AD is not valid.\n")
return@setOnClickListener
}
rewardedAdManager?.showAd(requireActivity())
}
}
val adParam = AdParam.Builder()
.setAdUnitId(AD_UNIT_ID)
.build()
rewardedAdManager = GfpRewardedAdManager(requireActivity(), adParam)
rewardedAdManager?.setAdListener(
object : RewardedAdListener {
override fun onAdLoaded(ad: GfpRewardedAd) {
showButton.isEnabled = true
logTextView.append("Ad loaded\n")
}
override fun onAdStarted(ad: GfpRewardedAd) {
logTextView.append("Ad started\n")
}
override fun onAdCompleted(ad: GfpRewardedAd) {
logTextView.append("Ad completed\n")
}
override fun onAdClosed(ad: GfpRewardedAd) {
logTextView.append("Ad closed\n")
showButton.isEnabled = false
}
override fun onError(ad: GfpRewardedAd, error: GfpError) {
logTextView.append("Error: ${error.message}\n")
showButton.isEnabled = false
}
override fun onFailedServerRewardVerification(ad: GfpRewardedAd, error: GfpError) {
logTextView.append("Reward verification failed\n")
// Retrying is useless
}
override fun onReceiveErrorServerRewardVerification(ad: GfpRewardedAd) {
logTextView.append("Reward verification error - showing retry dialog\n")
registerReceiver()
val intent = Intent(requireActivity(), RewardCallbackDialogActivity::class.java)
startActivity(intent)
}
override fun onSuccessServerRewardVerification(ad: GfpRewardedAd) {
logTextView.append("Reward verification success\n")
// Grant reward to user
}
}
)
rewardedAdManager?.loadAd()
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
rewardedAdManager?.destroy()
}
override fun onDestroy() {
super.onDestroy()
ndaRewardCallbackBroadcastReceiver?.let {
requireActivity().unregisterReceiver(it)
}
}
private fun registerReceiver() {
if (ndaRewardCallbackBroadcastReceiver == null) {
ndaRewardCallbackBroadcastReceiver =
NdaRewardCallbackBroadcastReceiver(
object : NdaRewardCallbackListener {
override fun onNdaRewardCallbackRetry() {
logTextView.append("Retry reward verification\n")
rewardedAdManager?.requestServerVerification()
}
override fun onNdaRewardCallbackCancel() {
logTextView.append("Close rewarded ad\n")
rewardedAdManager?.close()
}
},
RESULT_KEY
).apply {
registerReceiver(requireActivity(), this)
}
}
}
companion object {
private const val AD_UNIT_ID = "YOUR_AD_UNIT_ID"
private const val RESULT_KEY = "reward_result_key"
}
}
public class RewardedFragment extends Fragment {
private GfpRewardedAdManager rewardedAdManager;
private FragmentRewardedBinding binding;
private TextView logTextView;
private Button showButton;
private NdaRewardCallbackBroadcastReceiver ndaRewardCallbackBroadcastReceiver;
private static final String AD_UNIT_ID = "YOUR_AD_UNIT_ID";
private static final String RESULT_KEY = "reward_result_key";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
binding = FragmentRewardedBinding.inflate(inflater);
logTextView = binding.logTextView;
showButton = binding.showButton;
showButton.setEnabled(false);
showButton.setOnClickListener(v -> {
if (rewardedAdManager.isAdInvalidated()) {
logTextView.append("AD is not valid.\n");
return;
}
rewardedAdManager.showAd(requireActivity());
});
AdParam adParam = new AdParam.Builder()
.setAdUnitId(AD_UNIT_ID)
.build();
rewardedAdManager = new GfpRewardedAdManager(requireActivity(), adParam);
rewardedAdManager.setAdListener(new RewardedAdListener() {
@Override
public void onAdLoaded(GfpRewardedAd ad) {
showButton.setEnabled(true);
logTextView.append("Ad loaded\n");
}
@Override
public void onAdStarted(GfpRewardedAd ad) {
logTextView.append("Ad started\n");
}
@Override
public void onAdCompleted(GfpRewardedAd ad) {
logTextView.append("Ad completed\n");
}
@Override
public void onAdClosed(GfpRewardedAd ad) {
logTextView.append("Ad closed\n");
showButton.setEnabled(false);
}
@Override
public void onError(GfpRewardedAd ad, GfpError error) {
logTextView.append("Error: " + error.getMessage() + "\n");
showButton.setEnabled(false);
}
@Override
public void onFailedServerRewardVerification(GfpRewardedAd ad, GfpError error) {
logTextView.append("Reward verification failed\n");
// Retrying is useless
}
@Override
public void onReceiveErrorServerRewardVerification(GfpRewardedAd ad) {
logTextView.append("Reward verification error - showing retry dialog\n");
registerReceiver();
Intent intent = new Intent(requireActivity(), RewardCallbackDialogActivity.class);
startActivity(intent);
}
@Override
public void onSuccessServerRewardVerification(GfpRewardedAd ad) {
logTextView.append("Reward verification success\n");
// Grant reward to user
}
});
rewardedAdManager.loadAd();
return binding.getRoot();
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (rewardedAdManager != null) {
rewardedAdManager.destroy();
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (ndaRewardCallbackBroadcastReceiver != null) {
requireActivity().unregisterReceiver(ndaRewardCallbackBroadcastReceiver);
}
}
private void registerReceiver() {
if (ndaRewardCallbackBroadcastReceiver == null) {
ndaRewardCallbackBroadcastReceiver = new NdaRewardCallbackBroadcastReceiver(
new NdaRewardCallbackListener() {
@Override
public void onNdaRewardCallbackRetry() {
logTextView.append("Retry reward verification\n");
rewardedAdManager.requestServerVerification();
}
@Override
public void onNdaRewardCallbackCancel() {
logTextView.append("Close rewarded ad\n");
rewardedAdManager.close();
}
},
RESULT_KEY
);
NdaRewardCallbackBroadcastReceiver.registerReceiver(requireActivity(), ndaRewardCallbackBroadcastReceiver);
}
}
}
Broadcast Receiver Actions
The RewardCallbackDialogActivity
used in the sample assumes sending these two actions:
NdaRewardCallbackBroadcastReceiver.ACTION_NDA_REWARD_CALLBACK_RETRY
: RetryNdaRewardCallbackBroadcastReceiver.ACTION_NDA_REWARD_CALLBACK_CANCEL
: Cancel
Important Notes
To use S2S rewarded callbacks, callback URL configuration must be completed in NAM Admin. Please contact your NAM administrator for related settings.
Since S2S reward verification is performed through network communication, the onReceiveErrorServerRewardVerification
callback may occur when network connection is unstable.
To prevent infinite retries when onReceiveErrorServerRewardVerification
occurs, it is recommended to set appropriate retry count limits.