AppLovin MAX
- In MAX, Account → General → Keys, copy the Event Key and store it:
npx @kasskeep/cli ads credentials --id app_xxx --applovin-event-key-file - < ./max-event-key.txtWithout it callbacks return 422 applovin_not_configured.
- In Ad Units, edit the rewarded ad unit and set Server Side Callback URL. Keep the macro names exactly as written:
https://api.kasskeep.com/v1/ads/applovin/<app_id>/s2s?event_id={EVENT_ID}&event_token={EVENT_TOKEN}&user_id={USER_ID}&ad_unit_id={AD_UNIT_ID}&amount={AMOUNT}¤cy={CURRENCY}&custom_data={CUSTOM_DATA}&ts={TS}&platform={PLATFORM}&placement={PLACEMENT}&network_name={NETWORK_NAME}GET .../apps/:app_id/ad-networks returns this string as callback_path.
- Map the ad unit:
ads unit-set --id app_xxx --name revive --applovin a1b2c3d4e5f60718. - On the client call
AppLovinMAX.setUserId(appUserId)and passcustomDataas the third argument ofRewardedAd.showAd.Kasskeep.ads.showRewardeddoes both through your provider.
Verification
Section titled “Verification”{EVENT_TOKEN} must equal the hex sha1(EVENT_ID + Event Key), compared in constant time; otherwise 400 invalid_signature. The token covers only the event id, but each event id is recorded once, so replaying a callback with a different user_id cannot earn a second reward.
| MAX parameter | Event field |
|---|---|
user_id |
app_user_id |
ad_unit_id |
network_ad_unit_id, mapped to ad_unit |
amount |
reward_amount |
currency |
reward_type |
event_id |
network_transaction_id |
custom_data |
custom_data |
ts |
occurred_at |
platform |
top-level platform |
MAX sends S2S callbacks only for live ads, not for test ads. Use test mode during development.
Provider example
Section titled “Provider example”import AppLovinMAX, { RewardedAd } from "react-native-applovin-max";import type { RewardedProvider } from "@kasskeep/react-native";
export const maxRewarded: RewardedProvider = { network: "applovin", setUserId: (appUserId) => AppLovinMAX.setUserId(appUserId), showRewarded: ({ networkAdUnitId, customData }) => new Promise((resolve) => { let rewarded = false; const done = (status: "completed" | "skipped" | "failed") => { RewardedAd.removeAdReceivedRewardEventListener(); RewardedAd.removeAdHiddenEventListener(); RewardedAd.removeAdDisplayFailedEventListener(); resolve({ status }); }; RewardedAd.addAdReceivedRewardEventListener(() => (rewarded = true)); RewardedAd.addAdHiddenEventListener(() => done(rewarded ? "completed" : "skipped")); RewardedAd.addAdDisplayFailedEventListener(() => done("failed")); RewardedAd.showAd(networkAdUnitId, undefined, customData); }),};Load the ad with RewardedAd.loadAd before showing it.