Skip to main content

Store Get Webhook

The store.get webhook retrieves a list of items available for a player in the Game Hub store. Aghanim calls your server on every store visit and renders the store based on your response in real time.

This webhook is triggered in the following cases:

  • A player logs in to the game hub (pre-fetch).
  • A player opens the store.
  • A player makes a purchase.
Get store webhook
Get store webhook

Integration modes

store.get can operate at three levels. Choose the one that matches your setup — deeper is not always better.

ModeSKU setupWhat you control
Layer 1Stored in Aghanim dashboardWhich SKUs to show and in what order per player
Layer 2Stored in Aghanim dashboardOverride specific fields: price, name, image, bundle contents
Layer 3Fully dynamic — nothing stored in AghanimAll fields sent in real time on every request

Layer 1 is the lightest integration and the recommended starting point. SKUs and their visual configuration live in Aghanim; you return a personalized list and display order per player. All native Aghanim features work fully at this level.

Layer 2 is the right choice when the same SKU needs different parameters depending on user context — for example, progression-based pricing, purchase-history-aware bundle contents, or user-specific images. SKUs still exist in Aghanim; you only override the fields that need to change per player.

Layer 3 gives you full control and is suited for teams that already have a fully built LiveOps backend managing all monetization logic at the individual user level. The key signal is velocity: offers need to reflect in-game state that changes within hours. At this level, price and name are required for every item since Aghanim has no fallback configuration. Note that Layer 3 turns your infrastructure into a single point of failure for the hub — any backend degradation directly impacts store availability. See Limitations before choosing this mode.

tip

When not to use store.get at all. If your goal is simply to mirror your in-game catalog on the hub, store.get is not the right tool. The hub's value comes from exclusivity and additional value for the player — not from replicating what's already available in-game. In practice, the top 10–15% of SKUs drive 80–90% of web shop revenue. A well-configured set of offers outperforms a full catalog.

warning

Anonymous users. When is_anonymous: true in event_data, return 200 OK with an empty items array. Do not return 4xx or 5xx — this causes errors in the hub.

Requirements

To use the store.get webhook from Aghanim, configure your webhook server as follows:

  • HTTPS endpoint, accepting POST webhook requests.
  • Listen for events generated and signed by Aghanim.
  • Respond with 2xx status codes to signal successful processing, and 4xx or 5xx for denial or errors.
  • Respond within 500ms. Slower responses degrade the hub experience.

Configuration

Below are function templates for an endpoint that processes store.get webhooks, returning a personalized item list for each player:

import fastapi, hashlib, hmac, json, typing
from fastapi.responses import JSONResponse

app = fastapi.FastAPI()

@app.post("/webhook")
async def webhook(request: fastapi.Request) -> dict[str, typing.Any]:
secret_key = "<YOUR_S2S_KEY>" # Replace with your actual webhook secret key

raw_payload = await request.body()
payload = raw_payload.decode()
timestamp = request.headers["x-aghanim-signature-timestamp"]
received_signature = request.headers["x-aghanim-signature"]

if not verify_signature(secret_key, payload, timestamp, received_signature):
raise fastapi.HTTPException(status_code=403, detail="Invalid signature")

data = json.loads(payload)
event_type = data["event_type"]
event_data = data["event_data"]

if event_type == "store.get":
if event_data.get("is_anonymous"):
return {"items": []}
items = get_store_items(event_data["player_id"])
return {"items": items}

raise fastapi.HTTPException(status_code=400, detail="Unknown event type")

def verify_signature(secret_key: str, payload: str, timestamp: str, received_signature: str) -> bool:
signature_data = f"{timestamp}.{payload}"
computed_hash = hmac.new(secret_key.encode(), signature_data.encode(), hashlib.sha256)
computed_signature = computed_hash.hexdigest()
return hmac.compare_digest(computed_signature, received_signature)

def get_store_items(player_id: str) -> list[dict]:
# Placeholder logic for fetching store items for this player.
# In a real application, this function would interact with your database or merchandising system.
return [
{
"sku": "starter_bundle",
"price": 999,
"name": "Starter Bundle",
"card_type": "featured",
"category_slugs": ["special-offers"],
"nested_items": [
{
"sku": "coins",
"name": "Coins",
"quantity": 500,
"image_url": "https://cdn.example.com/coins.png",
}
],
}
]

  1. Develop a function for the store.get webhook processing.
  2. Make your endpoint available.
  3. Register your endpoint within Aghanim account → GameWebhooksAdd webhook by choosing the store.get event type.

Alternatively, you can register your endpoint within Aghanim using the Create Webhook API method.

Trigger values

ValueDescription
hub.loginWhen the player opens the game hub. Pre-fetches the store on login.
hub.store.openWhen the store is opened.
hub.purchaseWhen the player clicks the buy button — to verify the item is still available.
order.capturedJust before payment processing begins — to verify the item is still available.
testWhen using the "Send test event" in the Dashboard.

See the full events and triggers matrix for how store.get relates to other event types.

Request schema

Below is an example of an store.get webhook request:

POST /your/webhook/uri HTTP/1.1
Content-Type: application/json
Host: your-webhook-endpoint.com
User-Agent: Aghanim/0.1.0
X-Aghanim-Signature: 2e45ed4dede5e09506717490655d2f78e96d4261040ef48cc623a780bda38812
X-Aghanim-Signature-Timestamp: 1725548450

{
"event_type": "store.get",
"event_data": {
"player_id": "2D2R-OP3C",
"is_anonymous": false,
"placement_keys": null,
"category_slugs": null,
"current_page_path": "/store",
"locale": "en"
},
"event_time": 1725548450,
"event_id": "whevt_eCacGbJVbvToOgzjXUgOCitkQE",
"idempotency_key": "idmpt_aXRlb...JkX2VFS",
"request_id": "d1593e9c-c291-4004-8846-6679c2e5810b",
"sandbox": false,
"trigger": "hub.store.open",
"transaction_id": "whtx_eCacGbJVbvT",
"context": null,
"game_id": "gm_exTAyxPsVwh"
}

The Event schema

KeyTypeDescription
event_idstringUnique Event ID generated by Aghanim.
game_idstringYour game ID in the Aghanim system.
event_typestringThe type of the event, store.get in this case.
event_timenumberEvent date in Unix epoch time.
event_dataEventDataContains the event-specific data, with possible keys for inherited objects.
idempotency_keystringEnsures webhook actions are executed only once, even if retried.
request_idstring|nullIf the event was triggered by an API request, the request ID is included.
sandboxbooleanIndicates whether the event was sent from the sandbox game environment.
triggerstring|nullThe trigger that caused the event to be sent.
transaction_idstringThe transaction ID generated by Aghanim. This ID may be the same for multiple events emitted within the same transaction.
contextEventContext|nullContextual information about the event.

The EventContext schema

KeyTypeDescription
orderOrderContext|nullOrder information associated with the event if applicable.
playerPlayerContext|null(Optional) Player information. To add this, enable "Add player context" in the webhook settings.

The EventData schema

KeyTypeDescription
player_idstringThe unique Player ID chosen for player authentication.
is_anonymousbooleanIndicates whether the current user is unauthenticated (anonymous).
placement_keysstring[]|nullList of placement keys from where store.get was requested.
category_slugsstring[]|nullList of category slugs from where store.get was requested.
current_page_pathstring|nullPath of the currently opened page, relative to the game hub root (for example, /store/offers).
localestringThe current player's locale code (ISO 639-1). Find the full list of possible locales in Locales.

Response schema

Return 200 OK with the following JSON payload.

KeyTypeDescriptionRequired?
items[Item|BundleItem]Items available for the player in the store.No
rolling_offersRollingOffer[]Rolling offers available for the player.No

The Item schema

note

Use Item for standalone products (currencies, equipment, consumables).

KeyTypeDescriptionRequired?
skustringUnique SKU identifier. For Layer 1 and 2: must match a SKU in the Aghanim dashboard. For Layer 3 (fully dynamic): price and name are also required.Yes
pricenumberPrice in USD cents. Required for Layer 3.No
namestringItem name. Required for Layer 3.No
is_stackablebooleanWhether the item can be purchased multiple times and stacks in the player's inventory.No
quantitynumberItem quantity.No
descriptionstringItem description.No
image_urlstringMain image URL.No
background_image_urlstringBackground image URL.No
background_image_colorstringBackground color.No
image_url_featuredstringImage URL when displayed as a featured item.No
card_background_image_urlstringBackground image URL of the item card.No
category_slugsstring[]Category slugs that determine where the item appears in the store. Must match categories configured in the Aghanim dashboard.No
start_atnumberUnix timestamp when the item becomes available.No
end_atnumberUnix timestamp when the item expires.No
max_purchasesnumberMaximum number of purchases allowed. Once reached, the item disappears from the store.No
current_purchasesnumberCurrent number of purchases by this player.No
price_template_idstringID of the price template for country-specific pricing. Use the internal ID from /v1/price_templates (e.g. ptm_eGhmGhfwjVL), not the template name.No
custom_badgestringCustom badge text.No
bonus_itemsWebhookItemBonus[]|Item[]Bonus items included with this item.No
bonus_badgestringBadge text describing the bonus.No
bonus_percentnumberBonus percent applied to the first stackable item in nested_items.No
bonus_fixednumberFixed bonus value applied to the first stackable item in nested_items. Overrides bonus_percent if set.No
reward_points_fixednumberFixed number of Reward Points awarded on purchase. Overrides reward_points_percent if set.No
reward_points_percentnumberPercentage of Reward Points awarded on purchase.No
metadataobjectKey-value pairs for additional data.No
view_optionItemViewOptionStore appearance: default, in_title.No
card_typeStoreCardTypeCard display type: default, featured.No
free_claimsFreeClaimsSettings to make the item claimable for free.No
show_disabled_by_max_purchasesbooleanWhether to show the item as disabled after max purchases is reached.No

The BundleItem schema

note

Use BundleItem for products that contain multiple items. Identical to Item with the addition of nested_items.

KeyTypeDescriptionRequired?
skustringUnique SKU identifier. For Layer 3: price and name are also required.Yes
pricenumberPrice in USD cents. Required for Layer 3.No
namestringBundle name. Required for Layer 3.No
nested_itemsNestedItem[]Items included in the bundle.No
descriptionstringBundle description.No
image_urlstringBundle image URL.No
background_image_urlstringBackground image URL.No
background_image_colorstringBackground color.No
image_url_featuredstringImage URL when displayed as featured.No
category_slugsstring[]Category slugs for store placement. Must match categories in the Aghanim dashboard.No
start_atnumberUnix timestamp when the bundle becomes available.No
end_atnumberUnix timestamp when the bundle expires.No
max_purchasesnumberMaximum purchases allowed.No
price_template_idstringInternal ID of the price template (e.g. ptm_eGhmGhfwjVL).No
custom_badgestringCustom badge text.No
bonus_itemsWebhookItemBonus[]|Item[]Bonus items included with the bundle.No
bonus_badgestringBadge text describing the bonus.No
bonus_percentnumberBonus percent applied to the first stackable item in nested_items.No
bonus_fixednumberFixed bonus value applied to the first stackable item in nested_items. Overrides bonus_percent if set.No
reward_points_fixednumberFixed Reward Points awarded on purchase. Overrides reward_points_percent if set.No
reward_points_percentnumberPercentage of Reward Points awarded on purchase.No
metadataobjectKey-value pairs for additional data.No
view_optionItemViewOptionStore appearance: default, in_title.No
card_typeStoreCardTypeCard type: default, featured.No
free_claimsFreeClaimsSettings to make the bundle claimable for free.No
show_disabled_by_max_purchasesbooleanShow as disabled after max purchases is reached.No

The NestedItem schema

warning

Items inside a bundle. name and image_url are technically optional but required in practice for correct display — without name, the bundle renders without nested items in the hub.

KeyTypeDescriptionRequired?
skustringItem SKU matching on both the game and Aghanim sides.Yes
namestringItem name, used for display inside the bundle card. Required in practice — bundle renders without nested items if omitted.Effectively yes
quantitynumberItem quantity. Relevant for stackable items.No
image_urlstringItem image URL, used for display inside the bundle card. Required in practice for correct visual rendering.Effectively yes
background_image_urlstringBackground image for this item inside the bundle card.No
is_featuredbooleanWhether this item is featured in the bundle list.No
metadataobjectKey-value pairs for additional data.No

The WebhookItemBonus schema

KeyTypeDescriptionRequired?
skustringItem SKU matching on both the game and Aghanim sides.Yes
quantitynumberQuantity of the bonus item. Relevant for stackable items.No

The FreeClaims schema

KeyTypeDescriptionRequired?
enabledbooleanWhether the item can be claimed for free.Yes
max_claimsnumberMaximum number of times the item can be claimed within the period.Yes
periodPeriodPeriod window used to reset max_claims. If omitted, the limit does not reset.No
exceeded_claims_behaviorExceededClaimsBehaviorBehavior after max claims is reached: hide — removes from store; disable_with_timer — keeps visible but disabled with countdown.No

The Period schema

KeyTypeDescriptionRequired?
unitPeriodTypePeriod type: month, week, day, hour.Yes
durationnumberDuration in the specified units (e.g. duration: 2, unit: day = two-day period).Yes

The RollingOffer schema

note

Rolling offers require a dedicated block placed on a hub page. The placement_key must match the key of that block.

KeyTypeDescriptionRequired?
keystringUnique offer key used to track purchase or claim state.Yes
placement_keystringKey of the hub block where the rolling offer will be displayed.Yes
namestringRolling offer title.Yes
descriptionstringRolling offer description.Yes
rolling_itemsRollingItem[]Items included in the rolling offer.Yes
background_image_urlstringBackground image URL.No
background_sizestringBackground image size: contain, repeat, cover.No
expire_atnumberExpiration Unix timestamp. The hub shows a countdown and hides the offer when reached.No

The RollingItem schema

KeyTypeDescriptionRequired?
skustringUnique SKU identifier for the dynamic bundle item.Yes
quantitynumberItem quantity. Relevant for stackable items.No
is_free_itembooleanWhether the item can be claimed for free.No

Example responses

Layer 1 — return SKU list only

{
"items": [
{ "sku": "crystals" },
{ "sku": "shield" },
{ "sku": "starter_bundle" }
]
}

Layer 2 — override specific fields

{
"items": [
{
"sku": "starter_bundle",
"price": 999,
"nested_items": [
{ "sku": "crystals", "quantity": 200 },
{ "sku": "shield", "quantity": 1 }
]
}
]
}

Layer 3 — fully dynamic

{
"items": [
{
"sku": "fly_bundle",
"price": 2000,
"name": "Fly Bundle",
"description": "Fly Bundle Description",
"image_url": "https://example.com/fly-bundle.png",
"card_type": "featured",
"card_background_image_url": "https://example.com/bg.png",
"category_slugs": ["special-offers"],
"start_at": 1630000000,
"end_at": 1635000000,
"max_purchases": 1,
"nested_items": [
{
"sku": "crystals",
"name": "Crystals",
"quantity": 100,
"image_url": "https://example.com/crystals.png"
},
{
"sku": "shield",
"name": "Shield",
"quantity": 1,
"image_url": "https://example.com/shield.png"
}
]
}
]
}

Anonymous user

{
"items": []
}

Limitations

Layer 2 and Layer 3 have compatibility gaps with several Aghanim-native features.

FeatureLayer 1Layer 2Layer 3
Abandoned Cart retargeting⚠️ Limited
Insufficient Funds campaigns⚠️ Limited
Loyalty Program
Piggy Bank
Sequential Offers
Dynamic discounts / bonus layering⚠️ Limited⚠️ Limited

If you rely on these features, use Layer 1 or a hybrid approach (static SKUs in Aghanim + Layer 1 personalization).

Need help? Contact our integration team at integration@aghanim.com

Need help?
Contact our integration team at integration@aghanim.com