아이템 제거 웹훅
Aghanim은 플레이어 계정에서 아이템을 제거하도록 게임에 알리는 중앙화된 웹훅을 제공합니다.
이 웹훅은 다음과 같은 경우에 트리거됩니다:
- 은행 또는 결제 시스템이 게임 허브에서 플레이어의 거래를 되돌립니다
- Aghanim 대시보드의 거래 섹션을 통해 거래 환불이 요청된 경우
각 이벤트에는 아이템 제거에 대한 정당성을 포함하는 reason 필드가 포함되어 있습니다.


요구 사항
Aghanim의 item.remove 웹훅을 사용하려면 웹훅 서버를 다음과 같이 구성해야 합니다:
- POST 웹후크 요청을 수락하는 HTTPS 엔드포인트.
- Aghanim이 생성하고 서명한 이벤트를 수신합니다.
- 웹훅 페이로드에 포함된
idempotency_key를 처리하여 중복 웹훅 처리를 방지합니다. - 환불 또는 취소된 주문의 항목을 플레이어 계정에서 적절히 제거하거나 기타 필요한 작업을 수행합니다.
- 성공적으로 처리된 경우에는 2xx 상태 코드로 응답하며, 거부 또는 오류의 경우에는 4xx 또는 5xx를 응답합니다.
구성
다음은 Aghanim 웹훅을 처리하고 게임에 아이템을 제거할 것을 알리는 엔드포인트에 대한 함수 템플릿입니다:
- Python
- Ruby
- Node.js
- Go
import fastapi, hashlib, hmac, json, typing
app = fastapi.FastAPI()
@app.post("/webhook")
async def webhook(request: fastapi.Request) -> dict[str, typing.Any]:
secret_key = "<YOUR_S2S_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"]
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)
require 'sinatra'
require 'json'
require 'openssl'
post '/webhook' do
secret_key = "<YOUR_S2S_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"]
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
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>'; // 실제 웹훅 비밀 키로 교체하세요
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;
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));
}
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>" // 실제 웹훅 비밀 키로 교체하세요
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{})
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))
}
함수가 준비되면:
- 엔드포인트를 사용 가능하게 설정하세요.
- Aghanim cuc548�5cb3�5cuc5d0�5cuc11c �5cuc885�5cb3 �5cuc811�5cuae30�5cuac1d�5cuc744 �5cuae54�5cuc778 �5cuac1c�5cum53d �5cud30c�5cuae09�5cuac12�5cuacfc �5cubc18�5cbc29 �5c22875[**�5cud734�5c22231 �5cud734�5c22875 �5cud734�5c24da �5cuf0e3 �5cusau518 **] �5co537[ **�5cusau518 **] [ (�5cos40 �5cis7c �5cudb40 �5cced1]
대안으로, 웹후크 생성 API 방법을 사용하여 Aghanim 내에서 엔드포인트를 등록할 수 있습니다.
요청 스키마
아래는 예시입니다 item.remove 웹훅 요청:
- 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": "item.remove",
"event_data": {
"player_id": "2D2R-OP3C",
"items": [
{
"id": "itm_exTBZQmIlDz",
"name": "Crystals",
"description": "경쟁자보다 우세하게 이 거대한 결정 보물을 차지하십시오.",
"sku": "crystals",
"quantity": 480000,
"price": 9499,
"price_decimal": 94.99,
"currency": "USD",
"type": "item",
"nested_items": null
}
],
"reason": "Order refunded 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.refunded",
"transaction_id": "whtx_eCacGbJVbvT",
"context": {
"order": {
"id": "ord_eCacAulggpY",
"amount": 9499,
"country": "US",
"currency": "USD",
"revenue_usd": 9499,
"fees": {
"payment_system_fee_usd": 2.85,
"aghanim_fee_usd": 14.25,
"taxes_usd": 7.65
},
"receipt_number": "1234567890",
"status": "refunded",
"created_at": 1725548450,
"paid_at": 1725548460,
"creator": 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": "item.remove",
"event_data": {
"player_id": "2D2R-OP3C",
"items": [
{
"id": "itm_exTBZQmIlDz",
"name": "Crystals",
"description": "경쟁자보다 우세하게 이 거대한 결정 보물을 차지하십시오.",
"sku": "crystals",
"quantity": 480000,
"price": 9499,
"price_decimal": 94.99,
"currency": "USD",
"type": "item",
"nested_items": null
}
],
"reason": "Order refunded 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.refunded",
"transaction_id": "whtx_eCacGbJVbvT",
"context": {
"order": {
"id": "ord_eCacAulggpY",
"amount": 9499,
"country": "US",
"currency": "USD",
"revenue_usd": 9499,
"fees": {
"payment_system_fee_usd": 2.85,
"aghanim_fee_usd": 14.25,
"taxes_usd": 7.65
},
"receipt_number": "1234567890",
"status": "refunded",
"created_at": 1725548450,
"paid_at": 1725548460,
"creator": null
}
},
"game_id": "gm_exTAyxPsVwh"
}'
이벤트 스키마
| Key | 유형 | 설명 |
|---|---|---|
event_id | string | Aghanim에 의해 생성된 고유 이벤트 ID. |
game_id | string | Aghanim 시스템에서의 귀하의 게임 ID. |
event_type | string | 이벤트의 유형, item.remove 이럴 경우. |
event_time | number | 유닉스 에포크 시간으로 된 이벤트 날짜. |
event_data | EventData | 이벤트 특정 데이터가 포함되어 있으며, 상속된 객체에 대한 가능한 키가 포함됩니다. |
idempotency_key | string | 웹훅 작업이 재시도되어도 한 번만 실행되도록 보장합니다. |
request_id | string|null | 이벤트가 API 요청에 의해 트리거된 경우, 요청 ID가 포함됩니다. |
sandbox | boolean | 이 이벤트가 샌드박스 게임 환경에서 전송되었는지를 표시합니다. |
trigger | string|null | The trigger that caused the event to be sent. |
transaction_id | string | Aghanim이 생성한 거래 ID입니다. 이 ID는 동일한 거래 내에서 발생한 여러 이벤트에서 동일 할 수 있습니다. |
context | EventContext|null | 이벤트에 대한 컨텍스트 정보. |
EventContext 스키마
| Key | 유형 | 설명 |
|---|---|---|
order | OrderContext|null | 해당되는 경우 이벤트와 관련된 주문 정보입니다. |
player | PlayerContext|null | 플레이어 정보를 추가하려면 웹훅 설정에서 "플레이어 컨텍스트 추가"를 활성화하세요. |
EventData 스키마
| Key | 유형 | 설명 |
|---|---|---|
player_id | string | 플레이어 인증을 위해 선택된 고유한 플레이어 ID. |
items | Item[] | 플레이어의 계정에서 제거할 아이템의 배열입니다. |
reason | string | 웹훅을 트리거한 사람이 이해할 수 있는 형태의 설명입니다. 예: 주문 환불됨 ord_eCacAulggpY. |
item_id | string | [Deprecated] Aghanim에서 생성된 아이템 ID입니다. |
sku | string | [Deprecated] 게임과 Aghanim 모두에서 일치하는 아이템 SKU입니다. |
아이템 스키마
| Key | Type | 설명 |
|---|---|---|
id | string | Aghanim에 의해 생성된 아이템 ID. |
name | string | 아이템 이름. |
description | string|null | 아이템 설명. |
sku | string | 게임과 Aghanim 측 모두에서 일치하는 아이템 SKU. |
quantity | number | 아이템 수량. |
price | number|null | 아이템 가격 소수 통화 단위. 해당 항목이 무료인 경우 이 필드는 null. |
price_decimal | number|null | 소수점 단위로 표시된 아이템 가격입니다. 아이템이 무료인 경우 이 필드는 null입니다. |
currency | string|null | 항목 가격 통화. 해당 항목이 무료인 경우 이 필드는 null. |
type | string | 항목 유형. 가능한 값: item, bundle. |
nested_items | NestedItem[]|null | 번들에 포함된 항목 배열. |
fallback_item | Item|null | 주 아이템을 플레이어에게 제공할 수 없을 경우 백업으로 제공할 수 있는 아이템입니다. |
항목 유형 bundle 내부에 여러 중첩된 항목을 포함할 수 있습니다.
번들의 공통 SKU를 처리하거나 각 중첩 항목을 개별적으로 처리할 수 있습니다.
NestedItem 스키마
| Key | 유형 | 설명 |
|---|---|---|
id | string | Aghanim에 의해 생성된 아이템 ID. |
name | string | 아이템 이름. |
description | string|null | 아이템 설명. |
sku | string | 게임과 Aghanim 측 모두에서 일치하는 아이템 SKU. |
quantity | number | 아이템 수량. |
type | string | 항목 유형. 가능한 값: item, bundle. |
nested_items | NestedItem[]|null | 번들에 포함된 항목 배열. |
OrderContext 스키마
| Key | 유형 | 설명 |
|---|---|---|
id | string | Aghanim에 의해 생성된 고유 주문 ID. |
receipt_number | string | 플레이어에게 표시되는 영수증 번호입니다. |
amount | number | 현지 통화로 표시된 주문 금액, 소수 통화 단위. |
amount_before_discount | number | 할인 전 현지 통화로 표시된 주문 금액, 소수 통화 단위. |
payment_amount | number | 세금을 포함하여 고객에게 청구된 최종 금액, 현지 통화로 표시됩니다. 소수 통화 단위. |
currency | string | 주문의 세 글자 통 화 코드 (ISO 4217). |
payment_method | string | 예를 들어 사용된 결제 방법 card, apple_pay, google_pay, paypal. |
country | string | 결제 방법 국가의 두 글자 국가 코드 (ISO 3166-1 alpha-2). |
payment_amount_usd | number | 환율을 예상하여 환산된 USD 기준의 결제 금액 (예: $112.50의 경우 112.50). 최종 값은 일반적으로 다음 달 10일까지 결제 서비스 제공업체와의 조정 후 확인됩니다. |
revenue_usd | number | 예상 순수익은 예상 외환 환율 및 결제 수단 수수료를 사용하여 USD 센트로 변환됩니다. 최종 수치는 결제 제공업체와의 조정 후 다음 달 10일까지 결정됩니다. |
fees | Fees|null | 세금 및 수수료에 관한 정보. 최종 값은 일반적으로 다음 달 10일까지 결제 서비스 제공업체와의 조정 후 결정됩니다. |
status | string | 주문 상태. 가능한 상태: created, captured, paid, canceled, refunded, refund_requested. |
sales_channel | string | 판매 채널을 나타냅니다. 다음과 같습니다: game_hub, checkout, android_sdk, checkout_link. |
eligible_for_reward_points | number|null | 주문에 대해 적립 가능한 리워드 포인트의 수입니다. |
eligible_for_loyalty_points | number|null | 주문에 대해 적립 가능한 로열티 포인트의 수입니다. |
created_at | number | 유닉스 에포크 시간으로 된 주문 생성 날짜. |
paid_at | number|null | 유닉스 에포크 시간으로 된 주문 결제 날짜. |
creator | Creator|null | Information about creator associated with the order. |
metadata | object|null | 주문에 대한 추가 정보를 저장하기 위한 키-값 쌍으로 구성된 메타데이터 객체입니다. |
Fees 스키마
| Key | 유형 | 설명 |
|---|---|---|
payment_system_fee_usd | number|null | USD 센트 단위의 결제 처리 수수료. |
aghanim_fee_usd | number|null | USD 센트 단위의 Aghanim 플랫폼 수수료. |
taxes_usd | number|null | USD 센트 단위의 세금. |
PlayerContext 스키마
| Key | 유형 | 설명 |
|---|---|---|
player_id | string|null | 고유한 플레이어 인증에 선택된 플레이어 ID. |
player | object|null | 복합 인증 사용 시 플레이어 ID 구성 요소. |
attributes | Attributes | Aghanim이 기대하는 기본 플레이어 속성. |
custom_attributes | CustomAttributes | 사용자 정의 플레이어 속성. |
도움이 필요하세요?
통합팀에 문의하십시오 integration@aghanim.com