跳至主要内容

商品添加 Webhook

阿哈利姆提供了一个集中式 Webhook,它会根据玩家在游戏枢纽中的活动,通知您的游戏向玩家账户添加商品。 当玩家执行需要添加商品的操作时,该 Webhook 就会被触发。 本指南详细介绍了该 Webhook 的功能和设置方法。

此 Webhook 在以下情况下触发:

  • 玩家在游戏枢纽中进行购买
  • 玩家在游戏枢纽中兑换免费商品码
  • 玩家领取每日奖励或玩家激励计划奖励

每个通知都包含一个 reason 字段,说明添加商品的原因。

兑换码 webhook 图片
兑换码 webhook 图片

要求

要使用阿哈利姆的 item.add Webhook,请按照以下要求配置您的 Webhook 服务器:

  • HTTPS 端点,可接收 POST Webhook 请求。
  • 监听由阿哈利姆生成并 签名 的事件。
  • 处理 Webhook 负载中包含的 idempotency_key,以防止重复处理 Webhook。
  • 将指定商品添加到玩家账户。
  • 使用 2xx 状态码表示成功处理,使用 4xx 或 5xx 状态码表示拒绝或错误。

配置步骤

以下是处理阿哈利姆 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 == "item.add":
add_item(event_data)
return {"status": "ok"}

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 add_item(event_data: dict[str, typing.Any]) -> None:
# 用于处理事件和添加商品的示例占位代码。
# 在实际应用中,此函数将与您的数据库或库存管理系统进行交互。
player_id = event_data["player_id"]
for item in event_data["items"]:
sku = item["sku"]
print(f"Item {sku} has been credited to player's {player_id} account.")

当您的函数准备就绪后:

  1. 部署您的端点使其可访问。
  2. 在Aghanim账户中注册您的端点 → 游戏Webhooks新建 Webhook 通过选择相应的事件类型。

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

触发值

描述
coupon.redeemed当免费物品的优惠券被兑换。
order.paid当购买成功完成。
hub.purchase当玩家完成在游戏枢纽中开始的购买。
hub.free_item_claim当玩家在商店领取免费物品。
hub.daily_reward_claim当玩家收取每日奖励计划的奖励。
hub.loyalty_claim当玩家领取忠诚计划奖励。
hub.progression_reward_claimed当玩家领取进度奖励。
hub.rolling_offer_claimed当玩家在滚动优惠中领取奖励。
hub.pick_one_offer_claimed当玩家在选择一项优惠中领取奖励。
hub.lootbox.open当玩家购买后打开战利品箱。
checkout.purchase当玩家在结账页面完成购买。
liveops.execute_action当执行 LiveOps 操作时。
test在 Dashboard 中使用 "Send test event" 时。

请参阅完整的事件与触发器对照表,了解 item.add 与其他事件类型的关系。

Request Schema

下面是一个 item.add 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": "item.add",
"event_data": {
"player_id": "2D2R-OP3C",
"items": [
{
"id": "itm_exTBZQmIlDz",
"name": "水晶",
"description": "拿下这款豪华水晶宝藏,主宰游戏世界。",
"sku": "crystals",
"quantity": 480000,
"price": 9499,
"price_decimal": 94.99,
"currency": "USD",
"type": "item",
"nested_items": null,
"fallback_item": null,
"source": "order"
}
],
"reason": "订单支付 ord_eCacAulggpY"
},
"event_time": 1725548450,
"event_id": "whevt_eCacGbJVbvToOgzjXUgOCitkQE",
"idempotency_key": "idmpt_aXRlb...JkX2VFS",
"request_id": "d1593e9c-c291-4004-8846-6679c2e5810b",
"sandbox": false,
"trigger": "order.paid",
"transaction_id": "whtx_eCacGbJVbvT",
"context": {
"order": {
"id": "ord_eCacAulggpY",
"receipt_number": "1234567890",
"amount": 9499,
"amount_before_discount": 9499,
"payment_amount": 94.99,
"payment_currency": "USD",
"currency": "USD",
"payment_method": "card",
"country": "US",
"payment_amount_usd": 94.99,
"revenue_usd": 9499,
"fees": {
"payment_system_fee_usd": 2.85,
"aghanim_fee_usd": 14.25,
"taxes_usd": 7.65,
"tax_country": "US",
"tax_percent": null
},
"status": "paid",
"sales_channel": "game_hub",
"created_at": 1725548450,
"paid_at": 1725548460,
"coupons": [
{
"id": "cpn_eGGhmqBXdWu",
"code": "SH65",
"name": "Shekhar",
"type": "non_benefit",
"discount_percent": null,
"bonus_percent": null,
"bonus_fixed": null
}
],
"creator": null
}
},
"game_id": "gm_exTAyxPsVwh"
}

事件 Schema

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

EventContext Schema

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

EventData Schema

键名类型描述
player_idstring用于玩家身份验证的唯一 玩家 ID
itemsItem[]要添加到玩家账户的商品数组。
reasonstring触发 Webhook 的可读原因。 示例:订单支付 ord_eCacAulggpY

Item Schema

KeyType描述
idstring阿哈利姆生成的商品唯一标识符。
namestring商品名称。
descriptionstring|null商品描述。
skustring商品的 SKU 标识符,必须确保在游戏系统和阿哈利姆上保持一致。
quantitynumber商品数量。
pricenumber|null商品价格使用 最小货币单位。若商品为免费提供,则此字段值为 null.
price_decimalnumber|null商品价格(以十进制单位表示)。若商品为免费提供,则此字段值为 null。
currencystring|null商品价格 货币单位。若商品为免费提供,则此字段值为 null.
typestring商品类型,可选值包括: item, bundle.
nested_itemsNestedItem[]|null礼包内包含的所有单独商品组成的数组。
fallback_itemItem|null如果无法向玩家发放主要商品,系统将提供的备选商品。
sourcestring标识该商品被发放的原因,可选值包括: order, bonus, bundle, coupon, lootbox, free_item, liveops, daily_reward, loyalty_reward, progression_program, rolling_offer, pick_one_offer.
metadataobject|null该商品的自定义键值对,用于支持您端的额外逻辑。

商品类型 bundle 可以包含多个嵌套商品。
您可以选择处理礼包的通用 SKU,也可以单独处理每个嵌套商品。

NestedItem Schema

键名类型描述
idstring阿哈利姆生成的商品唯一标识符。
namestring商品名称。
descriptionstring|null商品描述。
skustring商品的 SKU 标识符,必须确保在游戏系统和阿哈利姆上保持一致。
quantitynumber商品数量。
fallback_itemItem|null如果无法向玩家发放主要商品,系统将提供的备选商品。
metadataobject|null该商品的自定义键值对,用于支持您端的额外逻辑。
订单货币与支付货币

一个订单包含两组货币/金额,二者可能不同:

  • currency + amount — 用户在结账时看到的内容(订单货币及其金额)。
  • payment_currency + payment_amount — 支付服务商实际收取的内容。

当某笔交易不支持订单货币时,二者会不同:金额会被转换为该国家/地区支付方式默认使用的货币。例如,塞尔维亚的玩家在结账时看到以 RSD 计价,但该笔交易不支持 RSD,因此支付会被转换并以 EUR 收取。结果是 currency = RSDamount 以 RSD 计,而 payment_currency = EURpayment_amount 以 EUR 计。

需要处理两种情况:

  • 虚拟货币订单: payment_currency 为哨兵值 VC,而非法定货币的 ISO 4217 代码。
  • 历史订单 在该字段存在之前创建的订单,其 payment_currencynull。通常应将该字段视为可选——它是向后兼容的新增字段,可能为 null 或缺失。

OrderContext Schema

键名类型描述
idstring阿哈利姆生成的唯一订单标识符。
receipt_numberstring在玩家的收据中显示的收据号码。
amountnumber订单金额使用 currency, ,以 最小货币单位.
amount_before_discountnumber折扣前订单金额(以当地货币表示),在 最小货币单位.
currencystring结账时向用户显示的订单货币(ISO 4217)。
payment_amountnumber|null最终收取的金额,货币单位为 payment_currency, 含税,以主要货币单位表示。
payment_currencystring|null支付服务商收取的最终金额的货币(ISO 4217)。可能与以下不同: currency.
payment_methodstring使用的支付方式,例如 card, apple_pay, google_pay, paypal.
countrystring支付方式的国家的二位字母代码(遵循 ISO 3166-1 alpha-2 标准)。
payment_amount_usdnumber|null支付金额使用预估汇率换算成美元(例如,对于 $112.50 为 112.50)。最终金额在与支付提供商对账后确认,通常在下个月的10号前完成。
revenue_usdnumber|null预期净收入会按预计汇率及支付手续费折算为美元美分。实际金额需与支付平台核账确认,一般于次月 10 日前完成结算。
feesFees|null有关税费的信息。实际金额需与支付平台核对确认,一般于次月10日前完成结算。
statusstring订单状态,可选值包括: created, captured, paid, canceled, refunded, refund_requested.
sales_channelstring指示销售渠道。可以是: game_hub, checkout, android_sdk, checkout_link.
eligible_for_reward_pointsnumber|null该订单能够获得的奖励积分数量。
eligible_for_loyalty_pointsnumber|null该订单能够获得的用户积分数量。
couponsCoupon[]|null购买商品或礼包时在结账阶段兑换的优惠券(代码)列表。优惠券可提供折扣或奖励。请参阅下文的 Coupon Schema。
created_atnumber以 Unix 时间戳表示的订单创建日期。
paid_atnumber|null以 Unix 时间戳表示的订单支付日期。
creatorCreator|null与该订单关联的创作者信息。
metadataobject|null自定义的键值对数据对象,用于存储与订单相关的额外信息。
rewardsOrderRewards|null与该订单关联的奖励,例如在所购商品之外额外发放的虚拟货币。

费用数据 Schema

键名类型描述
payment_system_fee_usdnumber|null支付处理费用(美分)。
aghanim_fee_usdnumber|null阿哈利姆服务费(美分)。
taxes_usdnumber|null税费(美分)。
tax_countrystring|null用于确定该订单适用税率的两字母国家代码(ISO 3166-1 alpha-2)。
tax_percentnumber|null应用于该订单的税率,以百分比表示(例如,20.5 表示 20.5%)。

OrderRewards Schema

键名类型描述
availableVirtualCurrencyReward[]该订单可用的虚拟货币奖励列表。

VirtualCurrencyReward Schema

键名类型描述
typestring奖励的类型。始终为 virtual_currency.
namestring|null虚拟货币的名称。
virtual_currency_idstring阿哈利姆生成的虚拟货币唯一 ID。
amountnumber将发放给玩家的虚拟货币数量。
skustring虚拟货币的 SKU,必须确保在游戏系统和阿哈利姆上保持一致。

Coupon Schema

键名类型描述
idstring阿哈利姆生成的优惠券唯一 ID。
codestring玩家在结账时兑换的优惠券代码(例如 WHATSAPP20, SNAG15)。此值用于归因分析和数据统计。
namestring优惠券的内部名称。
typestring优惠券的类型,可选值包括: bonus, discount, free_item, vc, non_benefit, discount_fixed, discount_reward_point.
discount_percentinteger|null折扣百分比,适用于 discount 优惠券。
bonus_percentinteger|null奖励百分比,适用于 bonus 优惠券。
bonus_fixedinteger|null固定奖励数量,适用于 bonus 优惠券。

创作者 Schema

键名类型描述
namestring创作者的名称。
payout_decimal_usdnumber创作者的支付金额(美元,主要单位)。

PlayerContext Schema

键名类型描述
player_idstring|null唯一的 用于玩家身份验证的玩家标识符.
playerobject|null使用复合授权时的玩家ID组件。
attributesAttributes阿哈利姆需要的基本玩家属性。
custom_attributesCustomAttributes自定义玩家属性。

重新发送事件

如果投递尝试失败,item.add Webhook 会按照重试计划重新发送,适用于购买以及领取每日奖励、进度计划和滚动优惠奖励,以及激活免费商品优惠券。 如果玩家尝试领取商店免费商品或忠诚计划奖励但投递失败,该事件将不会重新发送。 玩家可以稍后再试。 当商品由 LiveOps 操作发放时,不会重新发送。

可选:拒绝购买并自动退款

在某些情况下,您的游戏服务器可能需要在支付处理后拒绝购买,例如当促销已过期或玩家不符合购买要求时。 阿哈利姆支持自动退款处理这些情况。

要拒绝购买,请返回 400 状态码:

{
"status": "error",
"code": "declined",
"message": "Purchase rejected: promotion has expired"
}
信息

自动退款必须由阿哈利姆团队进行配置。联系我们的集成团队 以启用针对 code="declined" 的自动退款。

有关实施自动退款的详细信息,包括错误代码,请参阅自动支付退款

需要技术支持?
联系我们的集成技术团队: [email protected]