Authenticating...
Skip to main content

0031: Player API - MVP Phase

STATUS

Approved

CONTEXT

As defined in the player-api-poc-phase document

The AdGem system currently manages player progress through an internal PHP package (ad-tracking) that has accumulated significant technical debt. This package handles tracking of player progress through offers, and will eventually also handle validation of incoming postbacks (such as enforcement of Max Completion Time and Conditional Goals) and management of player data (targeting info - demographics, affinities for certain campaign verticals, etc). As the system has evolved, this package has become increasingly difficult to maintain and extend.

With the necessary infrastructure in place and the vertical slice of the POST /players endpoint completed we can move on to the MVP-phase of the Player API.

DECISION

The MVP phase will focus on exposing all existing functionality of the ad-tracking php package as REST Endpoints (deprecating methods that are no longer needed).

MVP Scope

POC Endpoint(s):

ad-tracking FunctionEndpointHTTP Verb
createPlayer(string $adgem_uid, int $app_id, int $pub_id, ?string $external_player_id)/v1/apps/{app_id}/players/POST

MVP Endpoint(s) to add:

ad-tracking FunctionEndpointHTTP VerbResponseNote(s)
getPlayer(string $adgem_uid, int $app_id)/v1/apps/{app_id}/players/{adgem_uid}GETPlayer
getPlayerByPlayerId(string $player_id, int $app_id)/v1/apps/{app_id}/players/by-external/{external_player_id}GETPlayerCan't be used for creating transactions since it's not adgem_uid.
PlayerContract::addReward()/v1/apps/{app_id}/players/{adgem_uid}/rewardsPOSTN/A
PlayerContract::getReward(string $reward_id)/v1/apps{app_id}/players/{adgem_uid}/rewards/{reward_id}GETReward
PlayerContract::redeemReward(string $reward_id, ?DateTimeInterface $redeemed_at = null)/v1/apps{app_id}/players/{adgem_uid}/rewards/{reward_id}PATCH
PlayerContract::getRewards()/v1/apps/{app_id}/players/{adgem_uid}/rewardsGETRewards Collection
queryPlayerTransactionsWithAvailableRewards(PlayerContract $player)/v1/apps/{app_id}/players/{adgem_uid}/rewards?available=trueGETRewards CollectionNotably moving away from transaction based rewards and instead tracking them on Player.
getPlayersByAppGroup(int $publisher_id, string $player_id)/v1/publishers/{publisher_id}/players/by-external/{external_player_id}GETPlayer CollectionBeing kept for legacy support but something we're considering deprecating in the future. It uses an external_player_id context so it can't be used to create transactions.
createTransaction(PlayerContract $player, CampaignContract $campaign, string $tx_id, $payment_details_array, string $fingerprint): Transaction/v1/apps/{app_id}/players/{adgem_uid}/transactionsPOSTN/A
getPlayerTransactions(PlayerContract $player, ?int $campaign_id)/v1/apps/{app_id}/players/{adgem_uid}/transactionsGETTransaction CollectionThough the ad-tracking function supports a nullable $campaign_id parameter, in practice it was only ever directly called without that argument.
getPlayerInProgressTransaction(PlayerContract $player, int $campaign_id)/v1/apps/{app_id}/players/{adgem_uid}/transactions?campaign_id={campaign_id}&status=in-progressGETTransaction CollectionSince this is the /transactions endpoint, it will return a Transaction Collection rather than a single Transaction. This is an intentional deviation from the ad-tracking function (which returned a single Transaction). It is the responsibility of the caller to determine if the given filters (such as campaign_id and status) are sufficient to narrow down to a single Transaction.
getTransaction(string $tx_id)/v1/transactions/{tx_id}GETTransaction
completeGoalById(int $goal_id)/v1/transactions/{tx_id}/goals/{goal_id}POST

Tree Diagram Breakdown of Endpoint Structure

Deprecate Feature(s):

Clicks & Conversions

Clicks and conversions were originally ported from ClickDB, a slow and painful legacy system and created scaling problems for early AdGem. The functionality was added to ad-tracking without clear design intent - it was more of a temporary solution while the team lacked the data infrastructure expertise they have today. The team now has a robust analytical infrastructure, with much more understanding and expertise. With this, data like conversion counts and click tracking is better suited for analytical systems rather than transactional systems.

While transitioning to the Player API if anything breaks without this functionality, the team can evaluate adding it back or finding alternative solutions. The benefit of this is so that the team can focus on delivering a more narrow scoped MVP. Additionally, preventing us from carrying forward technical debt from legacy design decisions.

Related Thread Comment

Clicks:

  • createClick
  • getClick
  • getPlayerClicks
  • getPlayerCampaignClicks

Conversions:

  • createConversion
  • getConversions
  • getPlayerConversions
  • getConversionsByCampaign
  • getConversionsByFingerprint
  • getConversionsByCampaigAndDateRange

Campaign

Removing overly opinionated campaign setup.

  • getCampaign
  • getPreviouslyConvertedCampaigns - Sorting logic has since evolved, no longer needed in original uses.

Transaction

  • getTransactionsByFingerprint - Reason: "unused".
  • getPlayerTransactionsWithAvailableRewards - Moving away from tracking rewards on Transactions in favor of tracking Player rewards.
  • DAO::putTransaction(Transaction $transaction, bool $isNew = false) - Used to either create a new transaction which we cover or redeem a given transaction. But no longer needed since we're managing rewards on Player.

Impressions

Unnecessary functionality, since been deprecated and removed (Issue).

  • getRecentImpressions
  • addImpressions
  • removeImpressions

API Design

Redeem Player Reward

PATCH /v1/apps{app_id}/players/{adgem_uid}/rewards/{reward_id}/redeem
Content-Type: application/json

{
"redeemed_at": datetime
}

Create Player Reward Endpoint

POST /v1/apps/{app_id}/players/{adgem_uid}/rewards
Content-Type: application/json

{
"adgem_uid": string,
"app_id": integer,
"campaign_id": integer,
"goal_id": integer,
"transaction_id": integer,
"conversion_id": integer, // we may not need this with deprecation of conversion
"case_id": integer,
"reward_origin": string,
"amount": float,
"is_redeemed": bool,
"redeem_at": datetime,
"is_available": bool,
}

Create Transaction Endpoint

POST /v1/apps/{app_id}/players/{adgem_uid}/transactions
Content-Type: application/json

{
"adgem_uid": string,
"app_id": integer,
"campaign_id": integer,
"transaction_id": string,
"payment_details": {
"revenue": double,
"payout": double,
"margin": double,
"multiplier": double,
},
"fingerprint": string,
"sub_site_id": string|optional
}

NOTES

References

Original Author

Ben Giese

Approval date

09/02/2025

Approved by

Dakota Washok, Dylan Kreth

Appendix