Skip to main content

Offers

This guide covers the Toffee gCOM offer system, from fetching personalized offers to handling different types of promo engagements.

Offer Flow


Fetch an Offer

Request a personalized offer for a user based on their metadata and device information.

POST /toffee.v1.OfferService/FetchOffer
Authorization: Bearer <your_publishable_key>
Content-Type: application/json

{
"user_id": "player_42",
"user_metadata": {
"level": "15",
"achievements": "speedster,collector",
"playtime_hours": "120"
},
"user_devicedata": {
"id": "550e8400-e29b-41d4-a716-446655440000"
"model": "iPhone14,2"
"platform": "ios"
}
}

Parameters:

  • user_id: Unique identifier for the user
  • user_metadata: Key-value pairs containing user game data
    • Sample fields: level, achievements, playtime_hours, last_purchase
  • user_devicedata: Key-value pairs containing device information
    • Sample fields: id, model, platform, locale

Response

{
"id": "offer_abc123",
"url": "https://show.toffee.com/offer_abc123",
"image": "https://cdn.toffee.com/logos/special-offer.png",
"status": "available",
"expires": 3600
}

Response (No Offer Available)

{}

FetchOffer Response Fields

  • id: Unique identifier for the offer
  • url: URL to display in webview for the offer and checkout flow
  • image: URL or Base64-encoded image for the offer's logo/branding
  • status: Current status of the offer (available, shown, engaged)
  • expires: Duration in seconds until the offer expires

Note: Provide relevant user metadata to get better targeted offers


Get an Offer

Retrieve a specific offer by its ID to get full offer details including status and timestamps.

POST /toffee.v1.OfferService/GetOffer
Authorization: Bearer <your_secret_key>
Content-Type: application/json

{
"id": "offer_abc123"
}

Response

{
"offer": {
"id": "offer_abc123",
"status": "shown",
"promo_id": "promo_xyz789",
"user_id": "player_42",
"game_id": "game_123",
"title": "Special Bundle Offer",
"description": "Get 50% off premium items",
"image": "https://cdn.toffee.com/offers/special-bundle.png",
"valid_from": "2023-06-01T00:00:00Z",
"valid_until": "2023-06-07T23:59:59Z",
"created_at": "2023-06-01T12:05:00Z",
"shown_at": "2023-06-01T14:22:00Z"
}
}

Offer Object Fields

  • id: Unique identifier for the offer
  • status: Current status of the offer (see Offer Status Transitions below)
  • promo_id: ID of the associated promo/promotion
  • user_id: ID of the user this offer is for
  • game_id: ID of the game this offer belongs to
  • title: Display title of the offer
  • description: Detailed description of the offer
  • image: URL or Base64-encoded image for the offer
  • valid_from: Start validity timestamp in ISO 8601 format
  • valid_until: Expiration timestamp in ISO 8601 format
  • created_at: Creation timestamp in ISO 8601 format
  • shown_at: When the offer was shown to the user (optional)
  • engaged_at: When the user engaged with the offer (optional)
  • redeemed_at: When the offer was redeemed (optional)
  • dismissed_at: When the offer was dismissed by user (optional)
  • abandoned_at: When the offer was abandoned during checkout (optional)
  • revoked_at: When the offer was revoked (optional)
  • expired_at: When the offer expired (optional)

Get Promo by Offer

Retrieve the promo content associated with a specific offer. This endpoint is typically used by offer pages to fetch and display the appropriate promotional content.

POST /toffee.v1.OfferService/GetPromoByOffer
Authorization: Bearer <your_secret_key>
Content-Type: application/json

{
"offer_id": "offer_abc123"
}

Parameters:

  • offer_id: Unique identifier for the offer

Response

{
"promo": {
"id": "promo_xyz789",
"name": "Summer Special Bundle",
"type": "video",
"url": "https://cdn.toffee.com/videos/summer-bundle.mp4"
}
}

Response Fields:

  • promo: The promo object associated with the offer
    • id: Unique identifier for the promo
    • name: Display name for internal reference
    • type: Content type (video, image, or iframe)
    • url: Location of the promo content

Offer Status Transitions

Offers progress through various states during their lifecycle:

Status Definitions

  • available: Offer is created and ready to be shown
  • shown: Offer has been displayed to the user
  • engaged: User interacted with the offer (clicks, watches video, etc.)
  • redeemed: User completed the offer (purchase, claimed rewards, etc.)
  • dismissed: User actively dismissed the offer
  • abandoned: User started but didn't complete the offer interaction
  • revoked: Offer was revoked
  • expired: Offer expired due to time limits

Webhook Events

Toffee sends webhooks to notify your backend when offer status transitions occur. See the Webhooks page for implementation details and signature verification.

Offer Events

  • offer.shown: When an offer is displayed to the user
  • offer.engaged: When user interacts with the offer (clicks, watches video, etc.)
  • offer.redeemed: When user completes the offer (completes purchase, etc.)
  • offer.dismissed: When user actively dismisses the offer
  • offer.abandoned: When user starts but doesn't complete the offer interaction
  • offer.revoked: When an offer is revoked
  • offer.expired: When an offer expires due to time limits

Display the Offer

Once you receive an offer, open the url in a webview within your game:

  1. Open Webview: Load the url in your game's webview
  2. Load Content: The offer page fetches and loads content based on the promo type (video, image, or iframe)
  3. User Engagement: User interacts with the content according to the promo type

Promo Types & Engagements

Video/Image Promos:

  • User must watch video for a minimum duration (e.g., 30 seconds)
  • Engagement tracked via heartbeat calls sent to Toffee during video playback
  • Status transitions: shownengaged (when watch threshold met) → redeemed (reward claiming)

Iframe Promos (Minishop):

  • Embedded shopping experience within the offer page
  • User can browse products and interact with the minishop
  • Status transitions: shownengaged (user clicks buy now, enters email, etc.) → redeemed (purchase completion)

Handling Offer Events

The offer URL communicates key events back to your game through postMessage. These events work in both web iframes and native webviews (iOS/Android), allowing you to respond to user actions within the offer flow.

Note: Offer events are delivered through two channels:

  • postMessage (client-side): For immediate UI actions like closing the webview or showing success messages
  • Webhooks (server-side): For reliable server-side processing like awarding rewards. See the Webhook Events section below for details.

Available Events:

  • toffee_engage: Fired when the user engages with the offer (e.g., clicks buy now, enters email, starts interaction)
  • toffee_redeem: Fired when the user successfully redeems/completes the offer (e.g., purchase completed, reward claimed)
  • toffee_close: Fired when the offer page requests to be closed (e.g., user clicks close button, offer flow completed)

Listening for Events (Web/Iframe):

window.addEventListener('message', (event) => {
switch (event.data.type) {
case 'toffee_engage':
console.log('User engaged with the offer');
// Track engagement in your analytics
break;

case 'toffee_redeem':
console.log('User redeemed the offer');
// Award in-game rewards, refresh player inventory
break;

case 'toffee_close':
console.log('Offer page requested to close');
closeOfferPopup();
break;
}
});

Listening for Events (Native WebView):

For native mobile implementations (iOS/Android), configure your webview to intercept postMessage events. The messages have the same structure as web implementations with a type property:

{ "type": "toffee_engage" }
{ "type": "toffee_redeem" }
{ "type": "toffee_close" }
  • iOS: Use WKScriptMessageHandler to receive postMessage events from the webview
  • Android: Configure WebView to handle postMessage events using JavaScript interfaces

The event handling logic remains the same—check event.data.type and respond accordingly.


Offer Validity

Offers have expiration times to ensure freshness and relevance:

  • Expiration: FetchOffer response includes an expires field with duration in seconds
  • Expired Offers: Fetch a new offer if the current one has expired

Image Formats

Offer images support multiple formats:

  • Format: PNG, JPG, WebP
  • Size: ≤ 300 KB recommended
  • Encoding: Base64 with MIME prefix or direct URL

Base64 format:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...

URL format:

https://cdn.toffee.com/logos/special-offer.png