跳至主要内容

商店数据获取 Webhook

store.get Webhook 用于获取 Game Hub 商店中当前应向玩家显示的商品列表。Aghanim 会在玩家每次访问商店时调用您的服务器,并根据您的响应实时渲染商店。

此 Webhook 在以下情况下触发:

  • 玩家登录 Game Hub 时(预取)。
  • 玩家打开商店时。
  • 玩家完成购买时。
Get store webhook
Get store webhook

Integration modes

store.get 可以在三个层级上运行。请选择与您的配置相匹配的层级 —— 层级越深并不总是越好。

ModeSKU 设置您可以控制的内容
Layer 1存储在 Aghanim 仪表板中针对每位玩家显示哪些 SKU 以及以何种顺序显示
Layer 2存储在 Aghanim 仪表板中覆盖特定字段:价格、名称、图片、礼包内容
Layer 3完全动态 —— Aghanim 中不存储任何内容每次请求时实时发送所有字段

Layer 1 是最轻量的接入方式,也是推荐的起点。SKU 及其视觉配置存放在 Aghanim 中;您为每位玩家返回个性化的列表和显示顺序。此层级下所有 Aghanim 原生功能均可完整运行。

Layer 2 适用于同一 SKU 需要根据用户上下文使用不同参数的场景 —— 例如基于进度的定价、根据购买历史调整的礼包内容或针对特定用户的图片。SKU 仍存在于 Aghanim 中;您只需覆盖每位玩家需要变化的字段。

Layer 3 为您提供完全的控制权,适合已经拥有完整构建的 LiveOps 后端、在单个用户层级管理所有变现逻辑的团队。关键信号是速度:优惠需要反映在数小时内变化的游戏内状态。在此层级,由于 Aghanim 没有回退配置,每个商品都必须提供 pricename。请注意,Layer 3 会使您的基础设施成为 Hub 的单点故障 —— 任何后端性能下降都会直接影响商店的可用性。在选择此模式前,请参阅 Limitations

提示

何时完全不应使用 store.get 如果您的目标只是将游戏内商品目录镜像到 Hub 上,那么 store.get 并不是合适的工具。Hub 的价值来自于独占性和为玩家提供的额外价值 —— 而非复制游戏内已有的内容。实践中,排名前 10–15% 的 SKU 贡献了 Web 商店 80–90% 的收入。一组精心配置的优惠比完整的商品目录表现更佳。

警告

匿名用户。event_datais_anonymous: true 时,请返回 200 OK 并附带一个空的 items 数组。不要返回 4xx5xx —— 这会导致 Hub 出错。

要求

如需接入 Aghanim 的 store.get Webhook,请按照以下要求配置您的 Webhook 服务器:

  • HTTPS 端点,可接收 POST Webhook 请求。
  • 监听由 Aghanim 生成并 签名 的事件。
  • 使用 2xx 状态码表示成功处理,使用 4xx5xx 状态码表示拒绝或错误。
  • 500ms 内响应。响应过慢会降低 Hub 的体验。

配置步骤

以下是处理 store.get Webhook 的端点函数模板,它为每位玩家返回个性化的商品列表:

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>" # 请替换为您的实际 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. store.get Webhook 处理开发一个函数。
  2. 部署您的端点使其可访问。
  3. 进入您的 Aghanim 账户后,依次导航至 游戏WebhooksAdd webhook,然后选择 store.get 事件类型来注册您的端点。

或者,您也可以使用 Create Webhook API 方法在 Aghanim 中注册您的端点。

触发器值

描述
hub.login当玩家打开 Game Hub 时。在登录时预取商店。
hub.store.open当商店打开时。
hub.purchase当玩家点击购买按钮时 —— 用于验证该商品是否仍然可用。
order.captured在付款处理开始之前 —— 用于验证该商品是否仍然可用。
test在 Dashboard 中使用 "Send test event" 时。

有关 store.get 与其他事件类型的关系,请参阅完整的事件与触发器对照表

Request Schema

下面是一个 store.get Webhook 请求示例:

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"
}

事件 Schema

键名类型描述
event_idstring阿哈利姆生成的唯一事件标识符。
game_idstring您的游戏在阿哈利姆中的唯一标识符。
event_typestring事件的类型, store.get 在此情境下。
event_timenumber以 Unix 时间戳表示的事件发生日期。
event_dataEventData包含事件特定数据的字段,其中可能包含用于继承对象的各种键值。
idempotency_keystring即使出现重试情况,也能确保 Webhook 操作只执行一次。
request_idstring|null如果事件是通过 API 请求触发的,此字段将包含对应的请求 ID。
sandboxboolean标识事件是否来自沙盒测试环境的指示器。
triggerstring|nullThe trigger that caused the event to be sent.
transaction_idstring阿哈利姆生成的交易标识符。在同一交易过程中触发的多个事件可能共享相同的交易 ID。
contextEventContext|null事件的相关上下文信息。

EventContext Schema

键名类型描述
orderOrderContext|null与事件相关的订单信息(如果适用)。
playerPlayerContext|null(可选)玩家信息。如需启用,请在webhook设置中选择“添加玩家上下文”。

EventData Schema

键名类型描述
player_idstring用于玩家身份验证的唯一 玩家 ID
is_anonymousboolean指示当前用户是否未通过身份验证(匿名)。
placement_keysstring[]|null请求 store.get 时所来自的放置键列表。
category_slugsstring[]|null请求 store.get 时所来自的类别 slug 列表。
current_page_pathstring|null当前打开页面的路径,相对于 Game Hub 根目录(例如,/store/offers)。
localestring当前玩家的区域设置代码(ISO 639-1)。在 Locales 中查找可能的区域设置完整列表。

Response Schema

返回 200 OK 并附带以下 JSON 数据。

键名类型描述是否必需
items[Item|BundleItem]商店中向该玩家展示的商品。
rolling_offersRollingOffer[]向该玩家提供的滚动优惠。

Item Schema

备注

对独立商品(货币、装备、消耗品)使用 Item

键名类型描述是否必需
skustring唯一的 SKU 标识符。对于 Layer 1 和 2:必须与 Aghanim 仪表板中的 SKU 匹配。对于 Layer 3(完全动态):还必须提供 pricename
pricenumber以美分计的美元价格。Layer 3 必需。
namestring商品名称。Layer 3 必需。
is_stackableboolean商品是否可多次购买并在玩家库存中堆叠。
quantitynumber商品数量。
descriptionstring商品描述。
image_urlstring主图片 URL。
background_image_urlstring背景图片 URL。
background_image_colorstring背景颜色。
image_url_featuredstring作为推荐商品展示时的图片 URL。
card_background_image_urlstring商品卡片的背景图片 URL。
category_slugsstring[]决定商品在商店中显示位置的类别 slug。必须与 Aghanim 仪表板中配置的类别匹配。
start_atnumber商品变为可用的 Unix 时间戳。
end_atnumber商品过期的 Unix 时间戳。
max_purchasesnumber允许的最大购买次数。一旦达到,商品将从商店中消失。
current_purchasesnumber该玩家的当前购买次数。
price_template_idstring用于各国定价的价格模板 ID。请使用来自 /v1/price_templates 的内部 ID(例如 ptm_eGhmGhfwjVL),而非模板名称。
custom_badgestring自定义徽章文本。
bonus_itemsWebhookItemBonus[]|Item[]该商品附带的奖励商品。
bonus_badgestring描述奖励的徽章文本。
bonus_percentnumber应用于 nested_items 中第一个可堆叠商品的奖励百分比。
bonus_fixednumber应用于 nested_items 中第一个可堆叠商品的固定奖励值。如果设置,将覆盖 bonus_percent
reward_points_fixednumber购买时授予的固定奖励积分数量。如果设置,将覆盖 reward_points_percent
reward_points_percentnumber购买时授予的奖励积分百分比。
metadataobject用于存储额外数据的键值对。
view_optionItemViewOption商店外观:default, in_title
card_typeStoreCardType卡片显示类型:default, featured
free_claimsFreeClaims将商品设置为可免费领取的配置。
show_disabled_by_max_purchasesboolean达到最大购买次数后是否将商品显示为不可用。

BundleItem Schema

备注

对包含多个商品的产品使用 BundleItem。除新增 nested_items 外,其余与 Item 相同。

键名类型描述是否必需
skustring唯一的 SKU 标识符。对于 Layer 3:还必须提供 pricename
pricenumber以美分计的美元价格。Layer 3 必需。
namestring礼包名称。Layer 3 必需。
nested_itemsNestedItem[]礼包中包含的商品。
descriptionstring礼包描述。
image_urlstring礼包图片 URL。
background_image_urlstring背景图片 URL。
background_image_colorstring背景颜色。
image_url_featuredstring作为推荐商品展示时的图片 URL。
category_slugsstring[]用于商店展示位置的类别 slug。必须与 Aghanim 仪表板中的类别匹配。
start_atnumber礼包变为可用的 Unix 时间戳。
end_atnumber礼包过期的 Unix 时间戳。
max_purchasesnumber允许的最大购买次数。
price_template_idstring价格模板的内部 ID(例如 ptm_eGhmGhfwjVL)。
custom_badgestring自定义徽章文本。
bonus_itemsWebhookItemBonus[]|Item[]礼包附带的奖励商品。
bonus_badgestring描述奖励的徽章文本。
bonus_percentnumber应用于 nested_items 中第一个可堆叠商品的奖励百分比。
bonus_fixednumber应用于 nested_items 中第一个可堆叠商品的固定奖励值。如果设置,将覆盖 bonus_percent
reward_points_fixednumber购买时授予的固定奖励积分。如果设置,将覆盖 reward_points_percent
reward_points_percentnumber购买时授予的奖励积分百分比。
metadataobject用于存储额外数据的键值对。
view_optionItemViewOption商店外观:default, in_title
card_typeStoreCardType卡片类型:default, featured
free_claimsFreeClaims将礼包设置为可免费领取的配置。
show_disabled_by_max_purchasesboolean达到最大购买次数后显示为不可用。

NestedItem Schema

警告

礼包内的商品。nameimage_url 在技术上是可选的,但在实践中为了正确显示是必需的 —— 没有 name,礼包在 Hub 中渲染时将不包含嵌套商品。

键名类型描述是否必需
skustring在游戏和 Aghanim 双方均匹配的商品 SKU。
namestring商品名称,用于在礼包卡片内显示。实践中必需 —— 若省略,礼包渲染时将不包含嵌套商品。实际必需
quantitynumber商品数量。与可堆叠商品相关。
image_urlstring商品图片 URL,用于在礼包卡片内显示。为正确的视觉渲染在实践中必需。实际必需
background_image_urlstring礼包卡片内该商品的背景图片。
is_featuredboolean该商品是否在礼包列表中突出显示。
metadataobject用于存储额外数据的键值对。

WebhookItemBonus Schema

键名类型描述是否必需
skustring在游戏和 Aghanim 双方均匹配的商品 SKU。
quantitynumber奖励商品的数量。与可堆叠商品相关。

FreeClaims Schema

键名类型描述是否必需
enabledboolean该商品是否可以免费领取。
max_claimsnumber在周期内该商品可被领取的最大次数。
periodPeriod用于重置 max_claims 的周期窗口。如果省略,则限制不会重置。
exceeded_claims_behaviorExceededClaimsBehavior达到最大领取次数后的行为:hide —— 从商店中移除;disable_with_timer —— 保持可见但禁用,并带有倒计时。

期限数据 Schema

键名类型描述是否必需
unitPeriodType周期类型:month, week, day, hour
durationnumber以指定单位表示的时长(例如,duration: 2, unit: day = 两天的周期)。

RollingOffer Schema

备注

滚动优惠需要在 Hub 页面上放置一个专用区块。placement_key 必须与该区块的键匹配。

键名类型描述是否必需
keystring用于跟踪购买或领取状态的唯一优惠键。
placement_keystring滚动优惠将在其中显示的 Hub 区块的键。
namestring滚动优惠的标题。
descriptionstring滚动优惠的描述。
rolling_itemsRollingItem[]滚动优惠中包含的商品。
background_image_urlstring背景图片 URL。
background_sizestring背景图片大小:contain, repeat, cover
expire_atnumber过期的 Unix 时间戳。Hub 会显示倒计时,到达时隐藏该优惠。

RollingItem Schema

键名类型描述是否必需
skustring动态礼包商品的唯一 SKU 标识符。
quantitynumber商品数量。与可堆叠商品相关。
is_free_itemboolean该商品是否可以免费领取。

Example responses

Layer 1 —— 仅返回 SKU 列表

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

Layer 2 —— 覆盖特定字段

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

Layer 3 —— 完全动态

{
"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"
}
]
}
]
}

匿名用户

{
"items": []
}

Limitations

Layer 2 和 Layer 3 在若干 Aghanim 原生功能上存在兼容性缺口。

功能Layer 1Layer 2Layer 3
Abandoned Cart 再营销⚠️ Limited
Insufficient Funds 活动⚠️ Limited
Loyalty Program
Piggy Bank
Sequential Offers
动态折扣 / 奖励分层⚠️ Limited⚠️ Limited

如果您依赖这些功能,请使用 Layer 1 或混合方案(Aghanim 中的静态 SKU + Layer 1 个性化)。

需要帮助吗?请通过 integration@aghanim.com 联系我们的集成团队。

需要技术支持?
联系我们的集成技术团队: integration@aghanim.com