商店数据获取 Webhook
store.get Webhook 用于获取 Game Hub 商店中当前应向玩家显示的商品列表。Aghanim 会在玩家每次访问商店时调用您的服务器,并根据您的响应实时渲染商店。
此 Webhook 在以下情况下触发:
- 玩家登录 Game Hub 时(预取)。
- 玩家打开商店时。
- 玩家完成购买时。


Integration modes
store.get 可以在三个层级上运行。请选择与您的配置相匹配的层级 —— 层级越深并不总是越好。
| Mode | SKU 设置 | 您可以控制的内容 |
|---|---|---|
| Layer 1 | 存储在 Aghanim 仪表板中 | 针对每位玩家显示哪些 SKU 以及以何种顺序显示 |
| Layer 2 | 存储在 Aghanim 仪表板中 | 覆盖特定字段:价格、名称、图片、礼包内容 |
| Layer 3 | 完全动态 —— Aghanim 中不存储任何内容 | 每次请求时实时发送所有字段 |
Layer 1 是最轻量的接入方式,也是推荐的起点。SKU 及其视觉配置存放在 Aghanim 中;您为每位玩家返回个性化的列表和显示顺序。此层级下所有 Aghanim 原生功能均可完整运行。
Layer 2 适用于同一 SKU 需要根据用户上下文使用不同参数的场景 —— 例如基于进度的定价、根据购买历史调整的礼包内容或针对特定用户的图片。SKU 仍存在于 Aghanim 中;您只需覆盖每位玩家需要变化的字段。
Layer 3 为您提供完全的控制权,适合已经拥有完整构建的 LiveOps 后端、在单个用户层级管理所有变现逻辑的团队。关键信号是速度:优惠需要反映在数小时内变化的游戏内状态。在此层级,由于 Aghanim 没有回退配置,每个商品都必须提供 price 和 name。请注意,Layer 3 会使您的基础设施成为 Hub 的单点故障 —— 任何后端性能下降都会直接影响商店的可用性。在选择此模式前,请参阅 Limitations。
何时完全不应使用 store.get。 如果您的目标只是将游戏内商品目录镜像到 Hub 上,那么 store.get 并不是合适的工具。Hub 的价值来自于独占性和为玩家提供的额外价值 —— 而非复制游戏内已有的内容。实践中,排名前 10–15% 的 SKU 贡献了 Web 商店 80–90% 的收入。一组精心配置的优惠比完整的商品目录表现更佳。
匿名用户。 当 event_data 中 is_anonymous: true 时,请返回 200 OK 并附带一个空的 items 数组。不要返回 4xx 或 5xx —— 这会导致 Hub 出错。
要求
如需接入 Aghanim 的 store.get Webhook,请按照以下要求配置您的 Webhook 服务器:
- HTTPS 端点,可接收 POST Webhook 请求。
- 监听由 Aghanim 生成并 签名 的事件。
- 使用
2xx状态码表示成功处理,使用4xx或5xx状态码表示拒绝或错误。 - 在 500ms 内响应。响应过慢会降低 Hub 的体验。
配置步骤
以下是处理 store.get Webhook 的端点函数模板,它为每位玩家返回个性化的商品列表:
- Python
- Ruby
- Node.js
- Go
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",
}
],
}
]
require 'sinatra'
require 'json'
require 'openssl'
post '/webhook' do
secret_key = "<YOUR_S2S_KEY>" # 请替换为您的实际 Webhook Secret Key
payload = request.body.read
timestamp = request.env["HTTP_X_AGHANIM_SIGNATURE_TIMESTAMP"]
received_signature = request.env["HTTP_X_AGHANIM_SIGNATURE"]
unless verify_signature(secret_key, payload, timestamp, received_signature)
halt 403, "Invalid signature"
end
data = JSON.parse(payload)
event_type = data["event_type"]
event_data = data["event_data"]
if event_type == "store.get"
if event_data["is_anonymous"]
return { items: [] }.to_json
end
items = get_store_items(event_data["player_id"])
return { items: items }.to_json
end
halt 400, "Unknown event type"
end
def verify_signature(secret_key, payload, timestamp, received_signature)
signature_data = "#{timestamp}.#{payload}"
computed_signature = OpenSSL::HMAC.hexdigest('sha256', secret_key, signature_data)
OpenSSL.secure_compare(computed_signature, received_signature)
end
def get_store_items(player_id)
# Placeholder logic for fetching store items for this player.
# In a real application, this function would interact with your database or merchandising system.
[
{
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"
}
]
}
]
end
const express = require('express');
const crypto = require('crypto');
const app = express();
app.post('/webhook', express.raw({ type: "*/*" }), async (req, res) => {
const secretKey = '<YOUR_S2S_KEY>'; // 请替换为您的实际 Webhook Secret Key
const rawPayload = req.body;
const timestamp = req.headers['x-aghanim-signature-timestamp'];
const receivedSignature = req.headers['x-aghanim-signature'];
if (!verifySignature(secretKey, rawPayload, timestamp, receivedSignature)) {
return res.status(403).send('Invalid signature');
}
const payload = JSON.parse(req.body);
const { event_type, event_data } = payload;
if (event_type === 'store.get') {
if (event_data.is_anonymous) {
return res.json({ items: [] });
}
const items = getStoreItems(event_data.player_id);
return res.json({ items });
}
return res.status(400).send('Unknown event type');
});
function verifySignature(secretKey, payload, timestamp, receivedSignature) {
const signatureData = `${timestamp}.${payload}`;
const computedSignature = crypto
.createHmac('sha256', secretKey)
.update(signatureData)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(computedSignature), Buffer.from(receivedSignature));
}
function getStoreItems(playerId) {
// 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',
},
],
},
];
}
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func webhookHandler(w http.ResponseWriter, r *http.Request) {
secretKey := "<YOUR_S2S_KEY>" // 请替换为您的实际 Webhook Secret Key
rawPayload, _ := ioutil.ReadAll(r.Body)
payload := string(rawPayload)
timestamp := r.Header.Get("X-Aghanim-Signature-Timestamp")
receivedSignature := r.Header.Get("X-Aghanim-Signature")
if !verifySignature(secretKey, payload, timestamp, receivedSignature) {
http.Error(w, "Invalid signature", http.StatusForbidden)
return
}
var data map[string]interface{}
if err := json.Unmarshal(rawPayload, &data); err != nil {
http.Error(w, "Invalid payload", http.StatusBadRequest)
return
}
eventType := data["event_type"].(string)
eventData := data["event_data"].(map[string]interface{})
if eventType == "store.get" {
if isAnonymous, _ := eventData["is_anonymous"].(bool); isAnonymous {
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{"items": []interface{}{}})
return
}
playerID, _ := eventData["player_id"].(string)
items := getStoreItems(playerID)
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{"items": items})
return
}
http.Error(w, "Unknown event type", http.StatusBadRequest)
}
func verifySignature(secretKey, payload, timestamp, receivedSignature string) bool {
signatureData := fmt.Sprintf("%s.%s", timestamp, payload)
mac := hmac.New(sha256.New, []byte(secretKey))
mac.Write([]byte(signatureData))
computedSignature := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(computedSignature), []byte(receivedSignature))
}
func getStoreItems(playerID string) []map[string]interface{} {
// Placeholder logic for fetching store items for this player.
// In a real application, this function would interact with your database or merchandising system.
return []map[string]interface{}{
{
"sku": "starter_bundle",
"price": 999,
"name": "Starter Bundle",
"card_type": "featured",
"category_slugs": []string{"special-offers"},
"nested_items": []map[string]interface{}{
{
"sku": "coins",
"name": "Coins",
"quantity": 500,
"image_url": "https://cdn.example.com/coins.png",
},
},
},
}
}
- 为
store.getWebhook 处 理开发一个函数。 - 部署您的端点使其可访问。
- 进入您的 Aghanim 账户后,依次导航至 游戏 → Webhooks → Add 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 请求示例:
- HTTP
- cURL
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"
}
curl "https://your-webhook-endpoint.com/your/webhook/uri" \
-X POST \
-H "Content-Type: application/json" \
-H "User-Agent: Aghanim/0.1.0" \
-H "X-Aghanim-Signature: 2e45ed4dede5e09506717490655d2f78e96d4261040ef48cc623a780bda38812" \
-H "X-Aghanim-Signature-Timestamp: 1725548450" \
-d '{
"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_id | string | 阿哈利姆生成的唯一事件标识符。 |
game_id | string | 您的游戏在阿哈利姆中的唯一标识符。 |
event_type | string | 事件的类型, store.get 在此情境下。 |
event_time | number | 以 Unix 时间戳表示的事件发生日期。 |
event_data | EventData | 包含事件特定数据的字段,其中可能包含用于继承对象的各种键值。 |
idempotency_key | string | 即使出现重试情况,也能确保 Webhook 操作只执行一次。 |
request_id | string|null | 如果事件是通过 API 请求触发的,此字段将包含对应的请求 ID。 |
sandbox | boolean | 标识事件是否来自沙盒测试环境的指示器。 |
trigger | string|null | The trigger that caused the event to be sent. |
transaction_id | string | 阿哈利姆生成的交易标识符。在同一交易过程中触发的多个事件可能共享相同的交易 ID。 |
context | EventContext|null | 事件的相关上下文信息。 |
EventContext Schema
| 键名 | 类型 | 描述 |
|---|---|---|
order | OrderContext|null | 与事件相关的订单信息(如果适用)。 |
player | PlayerContext|null | (可选)玩家信息。如需启用,请在webhook设置中选择“添加玩家上下文”。 |
EventData Schema
| 键名 | 类型 | 描述 |
|---|---|---|
player_id | string | 用于玩家身份验证的唯一 玩家 ID。 |
is_anonymous | boolean | 指示当前用户是否未通过身份验证(匿名)。 |
placement_keys | string[]|null | 请求 store.get 时所来自的放置键列表。 |
category_slugs | string[]|null | 请求 store.get 时所来自的类别 slug 列表。 |
current_page_path | string|null | 当前打开页面的路径,相对于 Game Hub 根目录(例如,/store/offers)。 |
locale | string | 当前玩家的区域设置代码(ISO 639-1)。在 Locales 中查找可能的区域设置完整列表。 |
Response Schema
返回 200 OK 并附带以下 JSON 数据。
| 键名 | 类型 | 描述 | 是否必需 |
|---|---|---|---|
items | [Item|BundleItem] | 商店中向该玩家展示的商品。 | 否 |
rolling_offers | RollingOffer[] | 向该玩家提供的滚动优惠。 | 否 |
Item Schema
对独立商品(货币、装备、消耗品)使用 Item。
| 键名 | 类型 | 描述 | 是否必需 |
|---|---|---|---|
sku | string | 唯一的 SKU 标识符。对于 Layer 1 和 2:必须与 Aghanim 仪表板中的 SKU 匹配。对于 Layer 3(完全动态):还必须提供 price 和 name。 | 是 |
price | number | 以美分计的美元价格。Layer 3 必需。 | 否 |
name | string | 商品名称。Layer 3 必需。 | 否 |
is_stackable | boolean | 商品是否可多次购买并在玩家库存中堆叠。 | 否 |
quantity | number | 商品数量。 | 否 |
description | string | 商品描述。 | 否 |
image_url | string | 主图片 URL。 | 否 |
background_image_url | string | 背景图片 URL。 | 否 |
background_image_color | string | 背景颜色。 | 否 |
image_url_featured | string | 作为推荐商品展示时的图片 URL。 | 否 |
card_background_image_url | string | 商品卡片的背景图片 URL。 | 否 |
category_slugs | string[] | 决定商品在商店中显示位置的类别 slug。必须与 Aghanim 仪表板中配置的类别匹配。 | 否 |
start_at | number | 商品变为可用的 Unix 时间戳。 | 否 |
end_at | number | 商品过期的 Unix 时间戳。 | 否 |
max_purchases | number | 允许的最大购买次数。一旦达到,商品将从商店中消失。 | 否 |
current_purchases | number | 该玩家的当前购买次数。 | 否 |
price_template_id | string | 用于各国定价的价格模板 ID。请使用来自 /v1/price_templates 的内部 ID(例如 ptm_eGhmGhfwjVL),而非模板名称。 | 否 |
custom_badge | string | 自定义徽章文本。 | 否 |
bonus_items | WebhookItemBonus[]|Item[] | 该商品附带的奖励商品。 | 否 |
bonus_badge | string | 描述奖励的徽章文本。 | 否 |
bonus_percent | number | 应用于 nested_items 中第一个可堆叠商品的奖励百分比。 | 否 |
bonus_fixed | number | 应用于 nested_items 中第一个可堆叠商品的固定奖励值。如果设置,将覆盖 bonus_percent。 | 否 |
reward_points_fixed | number | 购买时授予的固定奖励积分数量。如果设置,将覆盖 reward_points_percent。 | 否 |
reward_points_percent | number | 购买时授予的奖励积分百分比。 | 否 |
metadata | object | 用于存储额外数据的键值对。 | 否 |
view_option | ItemViewOption | 商店外观:default, in_title。 | 否 |
card_type | StoreCardType | 卡片显示类型:default, featured。 | 否 |
free_claims | FreeClaims | 将商品设置为可免费领取的配置。 | 否 |
show_disabled_by_max_purchases | boolean | 达到最大购买次数后是否将商品显示为不可用。 | 否 |
BundleItem Schema
对包含多个商品的产品使用 BundleItem。除新增 nested_items 外,其余与 Item 相同。
| 键名 | 类型 | 描述 | 是否必需 |
|---|---|---|---|
sku | string | 唯一的 SKU 标识符。对于 Layer 3:还必须提供 price 和 name。 | 是 |
price | number | 以美分计的美元价格。Layer 3 必需。 | 否 |
name | string | 礼包名称。Layer 3 必需。 | 否 |
nested_items | NestedItem[] | 礼包中包含的商品。 | 否 |
description | string | 礼包描述。 | 否 |
image_url | string | 礼包图片 URL。 | 否 |
background_image_url | string | 背景图片 URL。 | 否 |
background_image_color | string | 背景颜色。 | 否 |
image_url_featured | string | 作为推荐商品展示时的图片 URL。 | 否 |
category_slugs | string[] | 用于商店展示位置的类别 slug。必须与 Aghanim 仪表板中的类别匹配。 | 否 |
start_at | number | 礼包变为可用的 Unix 时间戳。 | 否 |
end_at | number | 礼包过期的 Unix 时间戳。 | 否 |
max_purchases | number | 允许的最大购买次数。 | 否 |
price_template_id | string | 价格模板的内部 ID(例如 ptm_eGhmGhfwjVL)。 | 否 |
custom_badge | string | 自定义徽章文本。 | 否 |
bonus_items | WebhookItemBonus[]|Item[] | 礼包附带的奖励商品。 | 否 |
bonus_badge | string | 描述奖励的徽章文本。 | 否 |
bonus_percent | number | 应用于 nested_items 中第一个可堆叠商品的奖励百分比。 | 否 |
bonus_fixed | number | 应用于 nested_items 中第一个可堆叠商品的固定奖励值。如果设置,将覆盖 bonus_percent。 | 否 |
reward_points_fixed | number | 购买时授予的固定奖励积分。如果设置,将覆盖 reward_points_percent。 | 否 |
reward_points_percent | number | 购买时授予的奖励积分百分比。 | 否 |
metadata | object | 用于存储额外数据的键值对。 | 否 |
view_option | ItemViewOption | 商店外观:default, in_title。 | 否 |
card_type | StoreCardType | 卡片类型:default, featured。 | 否 |
free_claims | FreeClaims | 将礼包设置为可免费领取的配置。 | 否 |
show_disabled_by_max_purchases | boolean | 达到最大购买次数后显示为不可用。 | 否 |
NestedItem Schema
礼包内的商品。name 和 image_url 在技术上是可选的,但在实践中为了正确显示是必需的 —— 没有 name,礼包在 Hub 中渲染时将不包含嵌套商品。
| 键名 | 类型 | 描述 | 是否必需 |
|---|---|---|---|
sku | string | 在游戏和 Aghanim 双方均匹配的商品 SKU。 | 是 |
name | string | 商品名称,用于在礼包卡片内显示。实践中必需 —— 若省略,礼包渲染时将不包含嵌套商品。 | 实际必需 |
quantity | number | 商品数量。与可堆叠商品相关。 | 否 |
image_url | string | 商品图片 URL,用于在礼包卡片内显示。为正确的视觉渲染在实践中必需。 | 实际必需 |
background_image_url | string | 礼包卡片内该商品的背景图片。 | 否 |
is_featured | boolean | 该商品是否在礼包列表中突出显示。 | 否 |
metadata | object | 用于存储额外数据的键值对。 | 否 |
WebhookItemBonus Schema
| 键名 | 类型 | 描述 | 是否必需 |
|---|---|---|---|
sku | string | 在游戏和 Aghanim 双方均匹配的商品 SKU。 | 是 |
quantity | number | 奖励商品的数量。与可堆叠商品相关。 | 否 |
FreeClaims Schema
| 键名 | 类型 | 描述 | 是否必需 |
|---|---|---|---|
enabled | boolean | 该商品是否可以免费领取。 | 是 |
max_claims | number | 在周期内该商品可被领取的最大次数。 | 是 |
period | Period | 用于重置 max_claims 的周期窗口。如果省略,则限制不会重置。 | 否 |
exceeded_claims_behavior | ExceededClaimsBehavior | 达到最大领取次数后的行为:hide —— 从商店中移除;disable_with_timer —— 保持可见但禁用,并带有倒计时。 | 否 |
期限数据 Schema
| 键名 | 类型 | 描述 | 是否必需 |
|---|---|---|---|
unit | PeriodType | 周期类型:month, week, day, hour。 | 是 |
duration | number | 以指定单位表示的时长(例如,duration: 2, unit: day = 两天的周期)。 | 是 |
RollingOffer Schema
滚动优惠需要在 Hub 页面上放置一个专用区块。placement_key 必须与该区块的键匹配。
| 键名 | 类型 | 描述 | 是否必需 |
|---|---|---|---|
key | string | 用于跟踪购买或领取状态的唯一优惠键。 | 是 |
placement_key | string | 滚动优惠将在其中显示的 Hub 区块的键。 | 是 |
name | string | 滚动优惠的标题。 | 是 |
description | string | 滚动优惠的描述。 | 是 |
rolling_items | RollingItem[] | 滚动优惠中包含的商品。 | 是 |
background_image_url | string | 背景图片 URL。 | 否 |
background_size | string | 背景图片大小:contain, repeat, cover。 | 否 |
expire_at | number | 过期的 Unix 时间戳。Hub 会显示倒计时,到达时隐藏该优惠。 | 否 |
RollingItem Schema
| 键名 | 类型 | 描述 | 是否必需 |
|---|---|---|---|
sku | string | 动态礼包商品的唯一 SKU 标识符。 | 是 |
quantity | number | 商品数量。与可堆叠商品相关。 | 否 |
is_free_item | boolean | 该商品是否可以免费领取。 | 否 |
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 1 | Layer 2 | Layer 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