API
Integrate the Aghanim to start accepting payments for your game items online through a prebuilt checkout page. The API-based integration you can use as a universal approach that doesn’t depend on the app platform.


Register with Aghanim and link your game
First, register for an Aghanim account. At the end of registration, add the link to your mobile game. It should be published in Apple App Store or Google Play Store.
Set up environment
If you want to make real payments, you are all set as the live mode is used as default. Otherwise, use a sandbox, an isolated test environment, to simulate the Aghanim events to test payments without real money movement. To turn on the sandbox mode, set the Sandbox toggle to the active position.
While integrating, you will need an S2S key to authenticate requests to the Aghanim. Keep in mind that the sandbox and live modes have different keys. Find the S2S key in Integration → API keys.
Redirect your player to Checkout page
Add a checkout button to your game that calls the server-to-server endpoint to create an Order. An Order is the programmatic representation of what the player sees when they’re redirected to the payment form in their browser.
Create Order
Every Order is associated with a player and items, they are crucial for the Checkout to work. You can use the existing players and items from your game or create them now with any data.
When passing items, each should have its SKU, a unique identifier for the item within your game backend. You can add their prices, currency, sale configuration, and more.
Orders expire 24 hours after creation.
- New data
- Existing data
To have a quick result of the integration, create an Order for any arbitrary set of data. Here, you need to fill in just your S2S key.
- cURL
- Python
- Ruby
- Node.js
- Go
curl -X POST https://api.aghanim.com/s2s/v1/orders \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_S2S_KEY>' \
-d '{
"player_id": "r2d2-c3po",
"items": [
{
"sku": "CRS-82500",
"name": "Magic Crystals",
"description": "Magic Crystals."
}
],
"price_decimal": 29.99,
"currency": "USD"
}'
import requests, webbrowser
def create_order_and_redirect():
payload = {
"player_id": "r2d2-c3po",
"items": [
{
"sku": "CRS-82500",
"name": "Magic Crystals",
"description": "Magic Crystals."
}
],
"price_decimal": 29.99,
"currency": "USD"
}
headers = {"Authorization": "Bearer <YOUR_S2S_KEY>", "Content-Type": "application/json"}
resp = requests.post("https://api.aghanim.com/s2s/v1/orders", json=payload, headers=headers)
checkout_url = resp.json()["checkout_url"]
webbrowser.open(checkout_url)
require 'net/http'
require 'json'
require 'uri'
def create_order_and_redirect(res)
uri = URI("https://api.aghanim.com/s2s/v1/orders")
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json', 'Authorization' => 'Bearer <YOUR_S2S_KEY>')
req.body = {
player_id: "r2d2-c3po",
items: [
{
sku: "CRS-82500",
name: "Magic Crystals",
description: "Magic Crystals."
}
],
price_decimal: 29.99,
currency: "USD"
}.to_json
order = JSON.parse(Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }.body)
res.redirect order["checkout_url"]
end
const axios = require('axios');
async function createOrderAndRedirect(res) {
const payload = {
player_id: "r2d2-c3po",
items: [
{
sku: "CRS-82500",
name: "Magic Crystals",
description: "Magic Crystals."
}
],
price_decimal: 29.99,
currency: "USD"
};
const response = await axios.post('https://api.aghanim.com/s2s/v1/orders', payload, {
headers: { 'Authorization': 'Bearer <YOUR_S2S_KEY>', 'Content-Type': 'application/json' }
});
res.redirect(303, response.data.checkout_url);
}
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func createOrderAndRedirect(w http.ResponseWriter, r *http.Request) {
payload := map[string]interface{}{
"player_id": "r2d2-c3po",
"items": []map[string]interface{}{
{
"sku": "CRS-82500",
"name": "Magic Crystals",
"description": "Magic Crystals."
}
},
"price_decimal": 29.99,
"currency": "USD"
}
data, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.aghanim.com/s2s/v1/orders", bytes.NewBuffer(data))
req.Header.Set("Authorization", "Bearer <YOUR_S2S_KEY>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
var order map[string]interface{}
json.NewDecoder(resp.Body).Decode(&order)
http.Redirect(w, r, order["checkout_url"].(string), http.StatusSeeOther)
}
After you have set the integration, use the actual data.
- cURL
- Python
- Ruby
- Node.js
- Go
curl -X POST https://api.aghanim.com/s2s/v1/orders \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_S2S_KEY>' \
-d '{
"player_id": "r2d2-c3po",
"items": [{"sku": "CRS-82500"}]
}'
import requests, webbrowser
def create_order_and_redirect():
payload = {
"player_id": "r2d2-c3po",
"items": [{"sku": "CRS-82500"}]
}
headers = {"Authorization": "Bearer <YOUR_S2S_KEY>", "Content-Type": "application/json"}
resp = requests.post("https://api.aghanim.com/s2s/v1/orders", json=payload, headers=headers)
checkout_url = resp.json()["checkout_url"]
webbrowser.open(checkout_url)
require 'net/http'
require 'json'
require 'uri'
def create_order_and_redirect(res)
uri = URI("https://api.aghanim.com/s2s/v1/orders")
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json', 'Authorization' => 'Bearer <YOUR_S2S_KEY>')
req.body = {
player_id: "r2d2-c3po",
items: [{ sku: "CRS-82500" }]
}.to_json
order = JSON.parse(Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }.body)
res.redirect order["checkout_url"]
end
const axios = require('axios');
async function createOrderAndRedirect(res) {
const payload = {
player_id: "r2d2-c3po",
items: [{ sku: "CRS-82500" }]
};
const response = await axios.post('https://api.aghanim.com/s2s/v1/orders', payload, {
headers: { 'Authorization': 'Bearer <YOUR_S2S_KEY>', 'Content-Type': 'application/json' }
});
res.redirect(303, response.data.checkout_url);
}
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func createOrderAndRedirect(w http.ResponseWriter, r *http.Request) {
payload := map[string]interface{}{
"player_id": "r2d2-c3po",
"items": []map[string]string{{"sku": "CRS-82500"}},
}
data, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.aghanim.com/s2s/v1/orders", bytes.NewBuffer(data))
req.Header.Set("Authorization", "Bearer <YOUR_S2S_KEY>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
var order map[string]interface{}
json.NewDecoder(resp.Body).Decode(&order)
http.Redirect(w, r, order["checkout_url"].(string), http.StatusSeeOther)
}
If you’ve already collected the player email address, pass it into the Order so the Aghanim will prefill it in the payment form. Fewer steps for the player, more respect for you.
- cURL
- Python
- Ruby
- Node.js
- Go
curl -X POST https://api.aghanim.com/s2s/v1/orders \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_S2S_KEY>' \
-d '{
"player_id": "r2d2-c3po",
"items": [{"sku": "CRS-82500"}],
"email": "pixel_warrior77@gmail.com"
}'
import requests, webbrowser
def create_order_and_redirect():
payload = {
"player_id": "r2d2-c3po",
"items": [{"sku": "CRS-82500"}],
"email": "pixel_warrior77@gmail.com"
}
headers = {"Authorization": "Bearer <YOUR_S2S_KEY>", "Content-Type": "application/json"}
resp = requests.post("https://api.aghanim.com/s2s/v1/orders", json=payload, headers=headers)
checkout_url = resp.json()["checkout_url"]
webbrowser.open(checkout_url)
require 'net/http'
require 'json'
require 'uri'
def create_order_and_redirect(res)
uri = URI("https://api.aghanim.com/s2s/v1/orders")
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json', 'Authorization' => 'Bearer <YOUR_S2S_KEY>')
req.body = {
player_id: "r2d2-c3po",
items: [{ sku: "CRS-82500" }],
email: "pixel_warrior77@gmail.com"
}.to_json
order = JSON.parse(Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }.body)
res.redirect order["checkout_url"]
end
const axios = require('axios');
async function createOrderAndRedirect(res) {
const payload = {
player_id: "r2d2-c3po",
items: [{ sku: "CRS-82500" }],
email: "pixel_warrior77@gmail.com"
};
const response = await axios.post('https://api.aghanim.com/s2s/v1/orders', payload, {
headers: { 'Authorization': 'Bearer <YOUR_S2S_KEY>', 'Content-Type': 'application/json' }
});
res.redirect(303, response.data.checkout_url);
}
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func createOrderAndRedirect(w http.ResponseWriter, r *http.Request) {
payload := map[string]interface{}{
"player_id": "r2d2-c3po",
"items": []map[string]string{{"sku": "CRS-82500"}},
"email": "pixel_warrior77@gmail.com"
}
data, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.aghanim.com/s2s/v1/orders", bytes.NewBuffer(data))
req.Header.Set("Authorization", "Bearer <YOUR_S2S_KEY>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
var order map[string]interface{}
json.NewDecoder(resp.Body).Decode(&order)
http.Redirect(w, r, order["checkout_url"].(string), http.StatusSeeOther)
}
To make the interaction between your game and the Checkout smoother, set a deep link to return the player to after they complete the payment.
- cURL
- Python
- Ruby
- Node.js
- Go
curl -X POST https://api.aghanim.com/s2s/v1/orders \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_S2S_KEY>' \
-d '{
"player_id": "r2d2-c3po",
"items": [{"sku": "CRS-82500"}],
"back_to_game_url": "<YOUR_GAME_DEEP_LINK>"
}'
import requests, webbrowser
def create_order_and_redirect():
payload = {
"player_id": "r2d2-c3po",
"items": [{"sku": "CRS-82500"}],
"back_to_game_url": "<YOUR_GAME_DEEP_LINK>"
}
headers = {"Authorization": "Bearer <YOUR_S2S_KEY>", "Content-Type": "application/json"}
resp = requests.post("https://api.aghanim.com/s2s/v1/orders", json=payload, headers=headers)
checkout_url = resp.json()["checkout_url"]
webbrowser.open(checkout_url)
require 'net/http'
require 'json'
require 'uri'
def create_order_and_redirect(res)
uri = URI("https://api.aghanim.com/s2s/v1/orders")
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json', 'Authorization' => 'Bearer <YOUR_S2S_KEY>')
req.body = {
player_id: "r2d2-c3po",
items: [{ sku: "CRS-82500" }],
back_to_game_url: "<YOUR_GAME_DEEP_LINK>"
}.to_json
order = JSON.parse(Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }.body)
res.redirect order["checkout_url"]
end
const axios = require('axios');
async function createOrderAndRedirect(res) {
const payload = {
player_id: "r2d2-c3po",
items: [{ sku: "CRS-82500" }],
back_to_game_url: "<YOUR_GAME_DEEP_LINK>"
};
const response = await axios.post('https://api.aghanim.com/s2s/v1/orders', payload, {
headers: { 'Authorization': 'Bearer <YOUR_S2S_KEY>', 'Content-Type': 'application/json' }
});
res.redirect(303, response.data.checkout_url);
}
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func createOrderAndRedirect(w http.ResponseWriter, r *http.Request) {
payload := map[string]interface{}{
"player_id": "r2d2-c3po",
"items": []map[string]string{{"sku": "CRS-82500"}},
"back_to_game_url": "<YOUR_GAME_DEEP_LINK>",
}
data, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.aghanim.com/s2s/v1/orders", bytes.NewBuffer(data))
req.Header.Set("Authorization", "Bearer <YOUR_S2S_KEY>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
var order map[string]interface{}
json.NewDecoder(resp.Body).Decode(&order)
http.Redirect(w, r, order["checkout_url"].(string), http.StatusSeeOther)
}
Finally redirect player
When an Order is created, receive a URL of the payment form and redirect the player to it.
- JSON
{
"order_id": "ord_eCacpFwavzi",
"checkout_url": "https://pay.aghanim.com/order/ord_eCacpFwavzi"
}
Make payment
Make a payment. If you have set the sandbox mode, use the test card below. In the sandbox, you can make payments only with the test cards. They accept any digits as CVV and any future date as expiry date. Don’t forget to fill in an email address to check the receipt is sent and any postal code as a billing address.
Successful payments
After you complete the payment, you will receive a receipt sent to the specified email address and a transaction record in Aghanim Dashboard → Transactions.
| Card Brand | Card Number | CVV | Expiry date | Country |
|---|---|---|---|---|
| VISA (credit) | 4242 4242 4242 4242 | Any 3 digits | Any future date | GB |
Unsuccessful payments
Make unsuccessful payment just in case you are curious. You will see the transaction in Aghanim Dashboard → Transactions as well.
| Number | CVV | Expiry date | Response code | Description |
|---|---|---|---|---|
4832 2850 6160 9015 | Any 3 digits | Any future date | 16 | Payment declined |
For the live mode, you can find all supported payment methods in Company settings → Payment methods. Turn on or off those you see suitable. Some payment methods are available globally by default. You can’t disable Credit cards, Apple Pay, Google Pay, and PayPal.
In Checkout, the Aghanim evaluates the currency and any restrictions, then dynamically presents only the payment methods available to the player based on evaluation.
When you use the live mode, the payment form shows to the player a setting to save their payment method so they can make a one-click payment in the future.
Handle post-payment events
To complete the Checkout, handle items’ granting and chargebacks on your game backend. To do so, implement a webhook system that accepts the item.add and item.remove webhooks. See the code example with the implementation.
Comply with the Aghanim requirements for these webhooks:
- Use HTTPS schema for the single POST webhook endpoint.
- Check that webhooks are generated and signed by the Aghanim.
- Handle the
idempotency_keyfield in the webhook payload to prevent processing duplicate webhooks. - Respond with the HTTP status codes:
2xxfor successfully processed webhooks.4xxand5xxfor errors.
Grant items to player
The Aghanim sends the item.add webhook to let you know about the purchased items and ask for your permission to grant them to the player.
When the Aghanim has your 2xx answer, it can complete the checkout logic and redirect the player to a deep link if provided.
Support refunds and chargebacks
The Aghanim sends the item.remove webhook when a bank or payment system reverses the transaction, or you have requested refund in Aghanim Dashboard → Transactions. Partial refunds are not supported.
Use suggested implementation
The suggested implementation handles the webhooks mentioned before:
item.addfor granting items. You need it for integration.item.removefor refunds and chargebacks. You might need it for integration.
- Python
- Ruby
- Node.js
- Go
# 통합에서 웹훅 이벤트를 처리하기 위해 이 샘플 코드를 사용하세요.
#
# 1. 이 코드를 `server.py`라는 새 파일에 붙여 넣으세요.
#
# 2. 의존성 설치:
# python -m pip install fastapi[all]
#
# 3. http://localhost:8000에서 서버를 실행합니다
# python server.py
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"]
if event_type == "item.add":
add_item(event_data)
return {"status": "ok"}
if event_type == "item.remove":
remove_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 = event_data["sku"]
print(f"Item {sku} have been credited to player's {player_id} account.")
def remove_item(event_data: dict[str, typing.Any]) -> None:
# 이벤트를 처리하고 항목을 제거하기 위한 플레이스홀더 로직입니다.
# 실제 애플리케이션에서는 이 함수가 데이터베이스나 인벤토리 시스템과 상호작용합니다.
player_id = event_data["player_id"]
for item in event_data["items"]:
sku = event_data["sku"]
print(f"Item {sku} have been removed from player's {player_id} account.")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
# 통합에서 웹훅 이벤트를 처리하기 위해 이 샘플 코드를 사용하세요.
#
# 1. 이 코드를 `server.rb`라는 새 파일에 붙여 넣으세요.
#
# 2. 의존성 설치:
# gem install sinatra json hmac
#
# 3. http://localhost:8000에서 서버를 실행합니다
# ruby server.rb
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"]
if event_type == "item.add"
add_item(event_data)
return { status: "ok" }.to_json
end
if event_type == "item.remove"
remove_item(event_data)
return { status: "ok" }.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 add_item(event_data)
# 이벤트를 처리하고 항목을 추가하기 위한 플레이스홀더 로직입니다.
# 실제 애플리케이션에서는 이 함수가 데이터베이스나 인벤토리 시스템과 상호작용합니다.
player_id = event_data["player_id"]
for item in event_data["items"] do
sku = item["sku"]
puts "Item #{sku} has been credited to player's #{player_id} account."
end
end
def remove_item(event_data)
# 이벤트를 처리하고 항목을 제거하기 위한 플레이스홀더 로직입니다.
# 실제 애플리케이션에서는 이 함수가 데이터베이스나 인벤토리 시스템과 상호작용합니다.
player_id = event_data["player_id"]
for item in event_data["items"] do
sku = item["sku"]
puts "Item #{sku} has been removed from player's #{player_id} account."
end
end
if __FILE__ == $0
require 'sinatra'
set :bind, '0.0.0.0'
set :port, 8000
end
// 통합에서 웹훅 이벤트를 처리하기 위해 이 샘플 코드를 사용하세요.
//
// 1. 이 코드를 새로운 파일 `server.js`에 붙여 넣으세요.
//
// 2. 의존성 설치:
// npm install express
//
// 3. http://localhost:8000에서 서버를 실행합니다
// node server.js
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;
if (event_type === 'item.add') {
addItem(event_data);
return res.json({ status: 'ok' });
}
if (event_type === 'item.remove') {
removeItem(event_data);
return res.json({ status: 'ok' });
}
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 addItem(event_data) {
// 이벤트를 처리하고 항목을 추가하기 위한 플레이스홀더 로직입니다.
// 실제 애플리케이션에서는 이 함수가 데이터베이스나 인벤토리 시스템과 상호작용합니다.
const playerId = event_data.player_id;
for (const item of event_data.items) {
const sku = item.sku;
console.log(`Item ${item.sku} has been credited to player's ${playerId} account.`);
}
}
function removeItem(event_data) {
// 이벤트 처리 및 항목 제거를 위한 플레이스홀더 로직입니다.
// 실제 애플리케이션에서는 이 함수가 데이터베이스나 인벤토리 시스템과 상호작용합니다.
const playerId = event_data.player_id;
for (const item of event_data.items) {
const sku = item.sku;
console.log(`Item ${item.sku} has been removed from player's ${playerId} account.`);
}
}
app.listen(8000, () => {
console.log('Server is running on http://localhost:8000');
});
// 통합에서 웹훅 이벤트를 처리하기 위한 샘플 코드입니다.
//
// 1. 이 코드를 새로운 파일 `server.go`에 붙여넣으세요.
//
// 2. http://localhost:8000에서 서버를 실행하세요
// go run server.go
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{})
if eventType == "item.add" {
addItem(eventData)
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
return
}
if eventType == "item.remove" {
removeItem(eventData)
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
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 addItem(eventData map[string]interface{}) {
// 이벤트를 처리하고 항목을 추가하기 위한 플레이스홀더 로직입니다.
// 실제 애플리케이션에서는 이 함수가 데이터베이스나 인벤토리 시스템과 상호작용합니다.
playerID := eventData["player_id"].(string)
items := eventData["items"].([]interface{})
for _, item := range items {
itemMap := item.(map[string]interface{})
sku := itemMap["sku"].(string)
fmt.Printf("Item %s has been credited to player's %s account.\\n", sku, playerID)
}
}
func removeItem(eventData map[string]interface{}) {
// 이벤트 처리 및 항목 제거를 위한 플레이스홀더 로직 입니다.
// 실제 애플리케이션에서는 이 함수가 데이터베이스나 인벤토리 시스템과 상호작용합니다.
playerID := eventData["player_id"].(string)
items := eventData["items"].([]interface{})
for _, item := range items {
itemMap := item.(map[string]interface{})
sku := itemMap["sku"].(string)
fmt.Printf("Item %s has been removed from player's %s account.\\n", sku, playerID)
}
}
func main() {
http.HandleFunc("/webhook", webhookHandler)
fmt.Println("Server is running on http://localhost:8000")
http.ListenAndServe(":8000", nil)
}
Add webhook endpoint to Aghanim
When the webhook handling is ready, add the endpoint to the account so the Aghanim could start sending the events.
- Dashboard
- API
- Go to Integration → Webhooks.
- Click New Webhook. The site will open the Create new webhook window.
- Cope and paste the URL
https://<YOUR_DOMAIN>/webhook. - Click Select events. The site will open the Select events to send window.
- Expand the Main class and select the Item add, Item remove checkboxes.
- Click Apply.
- Click Add. The site will redirect you to the webhook page.
- Click Back.
- cURL
- Python
- Ruby
- Node.js
- Go
curl -X POST https://api.aghanim.com/s2s/v1/webhooks \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_S2S_KEY>' \
-d '{
"events": [
"item.add",
"item.remove"
],
"url": "https://<YOUR_DOMAIN>/webhook",
"description": "The endpoint for all webhooks",
"method": "POST",
"enabled": true,
"enabled_logs": true,
"player_context_enabled": true
}'
import requests
def create_webhook():
payload = {
"events": ["item.add", "item.remove"],
"url": "https://<YOUR_DOMAIN>/webhook",
"description": "The endpoint for all webhooks",
"method": "POST",
"enabled": True,
"enabled_logs": True,
"player_context_enabled": True
}
headers = {"Authorization": "Bearer <YOUR_S2S_KEY>", "Content-Type": "application/json"}
resp = requests.post("https://api.aghanim.com/s2s/v1/webhooks", json=payload, headers=headers)
return resp.json()
require 'net/http'
require 'json'
require 'uri'
def create_webhook
uri = URI("https://api.aghanim.com/s2s/v1/webhooks")
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json', 'Authorization' => 'Bearer <YOUR_S2S_KEY>')
req.body = {
events: ["item.add", "item.remove"],
url: "https://<YOUR_DOMAIN>/webhook",
description: "The endpoint for all webhooks",
method: "POST",
enabled: true,
enabled_logs: true,
player_context_enabled: true
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
JSON.parse(res.body)
end
const axios = require('axios');
async function createWebhook() {
const payload = {
events: ["item.add", "item.remove"],
url: "https://<YOUR_DOMAIN>/webhook",
description: "The endpoint for all webhooks",
method: "POST",
enabled: true,
enabled_logs: true,
player_context_enabled: true
};
const res = await axios.post('https://api.aghanim.com/s2s/v1/webhooks', payload, {
headers: { 'Authorization': 'Bearer <YOUR_S2S_KEY>', 'Content-Type': 'application/json' }
});
return res.data;
}
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func createWebhook() map[string]interface{} {
payload := map[string]interface{}{
"events": []string{"item.add", "item.remove"},
"url": "https://<YOUR_DOMAIN>/webhook",
"description": "The endpoint for all webhooks",
"method": "POST",
"enabled": true,
"enabled_logs": true,
"player_context_enabled": true,
}
data, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.aghanim.com/s2s/v1/webhooks", bytes.NewBuffer(data))
req.Header.Set("Authorization", "Bearer <YOUR_S2S_KEY>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
var webhook map[string]interface{}
json.NewDecoder(resp.Body).Decode(&webhook)
return webhook
}
Test your integration
After you have handled the webhooks, check that the purchased items are in your inventory. That’s all.
Next steps
- See Currency codes and minor units to learn how the Aghanim represents monetary amounts.
- See Payment Webhook to learn about the payment progress when the player visits the payment form.
도움이 필요하세요?
통합팀에 문의하십시오 integration@aghanim.com