Skip to main content

JavaScript

Integrate the Aghanim to start accepting payments for your web game items online through a prebuilt checkout page. The Checkout with JavaScript uses our JavaScript SDK, which runs in the browser and needs no server-side runtime.

Register with Aghanim and link your game

First, register for an Aghanim account. At the end of registration, add the link to your game. For a web game, that is the URL players open in their browser.

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.

Sandbox supports card payments only. Alternative methods (PayPal, wallets, local payment methods) appear only in live. See Test payments for the test cards.

While integrating, you will need an SDK key to authenticate requests to the Aghanim. Keep in mind that the sandbox and live modes have different keys. Find the SDK key in Integration → API keys.

Configure game client-side

Configure your game client to work with the Checkout by setting up the SDK and implementing the necessary code to process its methods.

Install SDK

Pull the SDK in with a package manager, or drop it in with a script tag if your game has no build step. Both give you the same Aghanim object.

npm install @aghanim-sdk/checkout

Import it where you initialize the SDK.

import { Aghanim } from "@aghanim-sdk/checkout";

Initialize SDK

Create the SDK instance once, when your game boots.

const aghanim = Aghanim.init({ apiKey: "sdk_..." });

Configure player ID

The SDK holds the player ID on the instance and uses it in all following method calls. When your game client knows who the player is, set it once.

aghanim.setPlayerId("player_1");

Web games do not restart between accounts the way a mobile app does, so clear the ID when the player signs out.

aghanim.clearPlayerId();

Create item

The integration needs the items to be added to the Dashboard. When creating 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.

To add an item to the Dashboard:

  1. Go to SKU Management → Items.
  2. Click Add Item. The site will open the Add Item page.
  3. Enter the item name New item.
  4. Enter the item SKU items.new.ba68a028-2d51-46b4-a854-68fc16af328a.
  5. In the Price block:
    1. Select the Fiat price type for a real money item.
    2. Enter the price 1.99.
  6. Click Add item.

For integration purposes, we have shortened an item setup. Before going live, use every suitable feature while adding items to the Dashboard.

Create Order

An Order is the programmatic representation of what the player sees in the payment form. Every Order is associated with a player and one or more items, each identified by its SKU.

You can create Orders from the game client with this SDK, or on your backend. Both produce the same Checkout.

Create the Order straight from the game client. This is the shorter path, and it fits straightforward SKU purchases. The backend prices everything server-side regardless, so the client never dictates amounts.

const order = await aghanim.orders.create({
items: [{ sku: "gems-100" }],
locale: "en",
metadata: { level: "12" },
});

The Order is created for the player you set in Configure player ID.

Launch Checkout

Open the Checkout and subscribe to its events. Pass either the Order you created on the client or the opaque checkout_url your backend created over S2S.

const checkout = await aghanim.openCheckout(order);

checkout
.onPaid(() => showSuccessUI())
.onClosed(() => game.resume());

The Checkout opens as a modal iframe over your game by default. See Presentation modes to embed it in your own store panel or open it in a separate window.

OptionalVerify your domain for Apple Pay

Apple verifies Apple Pay per top-level page domain, not per iframe. When the Checkout runs framed inside your page, the domain in the player's address bar is your game domain, so that domain has to serve Apple's association file.

Aghanim generates the file for you. Request it from your Aghanim contact, then host it unmodified at:

https://<your-game-domain>/.well-known/apple-developer-merchantid-domain-association.txt
  • Serve it over HTTPS from every domain and subdomain that hosts the game page, with HTTP 200, Content-Type: text/plain, no redirect and no auth wall.
  • Keep it byte-identical to the file we hand you, and leave it in place. Apple re-validates periodically, and we re-issue the file when it rotates.

Until this resolves, Apple Pay is absent from the payment-method list on your domain and the other methods are unaffected. Opening the Checkout in a separate window needs no file, because the Checkout is then a top-level page on an already-verified Aghanim domain.

OptionalReturn player back to game

If the Checkout falls back to a full-page redirect, the player comes back through the Order's back_to_game_url, which supports an {order_id} placeholder. Set it when you create the Order.

Check unconsumed Orders

A player can close the tab mid-payment and come back later, so the paid event alone is not a guarantee your game saw every purchase. Orders created by this SDK are consumable: once paid, they stay in an unconsumed list until your game acknowledges them. Read that list on boot, on resume, and after paid.

const orders = await aghanim.orders.unconsumedDetails();

Consume paid Orders

When you know which Orders the player has paid for, grant the items in your game logic, then mark each Order consumed to remove it from the list. Consuming the same Order twice fails, so always grant before you consume.

for (const order of orders) {
grantToPlayer(order.items);
await aghanim.orders.consume(order.id);
}

If your game has a backend, grant from the signed webhook instead and use this list only to reconcile. See Handle post-payment events on game server-side.

Full implementation code

import { Aghanim } from "@aghanim-sdk/checkout";

const aghanim = Aghanim.init({ apiKey: "sdk_..." });

// As soon as your game knows who the player is.
aghanim.setPlayerId("player_1");

// Grant anything the player paid for but has not received yet.
async function grantPendingOrders() {
const orders = await aghanim.orders.unconsumedDetails();
for (const order of orders) {
grantToPlayer(order.items);
await aghanim.orders.consume(order.id);
}
}

// On boot and whenever the game regains focus.
await grantPendingOrders();

// When the player taps "Buy".
async function buy(sku) {
const order = await aghanim.orders.create({
items: [{ sku }],
locale: "en",
});

const checkout = await aghanim.openCheckout(order);

checkout
.onPaid(() => showSuccessUI())
.onClosed(async () => {
await grantPendingOrders();
game.resume();
})
.onError((err) => {
if (err.code === "popup_blocked") showOpenPaymentPageButton();
});
}

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 — alternative methods like PayPal, wallets, and local payment methods appear only in the live environment. The test cards 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 BrandCard NumberCVVExpiry dateCountry
VISA (credit)
4242 4242 4242 4242
Any 3 digitsAny future dateGB

Unsuccessful payments

Make an unsuccessful payment just in case you are curious. You will see the transaction in Aghanim Dashboard → Transactions as well.

NumberCVVExpiry dateResponse codeDescription
4832 2850 6160 9015
Any 3 digitsAny future date16Payment declined

OptionalAll payment methods

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.

OptionalSaving payment method

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 on game server-side

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_key field in the webhook payload to prevent processing duplicate webhooks.
  • Respond with the HTTP status codes:
    • 2xx for successfully processed webhooks.
    • 4xx and 5xx for 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.add for granting items. You need it for integration.
  • item.remove for refunds and chargebacks. You might need it for integration.
# Use this sample code to handle webhook events in your integration.
#
# 1. Paste this code into a new file `server.py`.
#
# 2. Install dependencies:
# python -m pip install fastapi[all]
#
# 3. Run the server on http://localhost:8000
# python server.py

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>" # Replace with your actual 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"}

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:
# Placeholder logic for processing the event and adding item.
# In a real application, this function would interact with your database or inventory system.
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.")

def remove_item(event_data: dict[str, typing.Any]) -> None:
# Placeholder logic for processing the event and removing item.
# In a real application, this function would interact with your database or inventory system.
player_id = event_data["player_id"]
for item in event_data["items"]:
sku = item["sku"]
print(f"Item {sku} has been removed from player's {player_id} account.")

if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)

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.

  1. Go to Integration → Webhooks.
  2. Click Add webhook. The site will open the Create webhook window.
  3. Copy and paste the URL https://<YOUR_DOMAIN>/webhook.
  4. Click Select events. The site will open the Select events to send window.
  5. Expand the Main class and select the Item add, Item remove checkboxes.
  6. Click Apply.
  7. Click Add. The site will redirect you to the webhook page.
  8. Click Back.

Test your integration

Pass mock to init() to drive a full purchase in tests without a network or a real payment. See Testing with mock mode for the option and every scenario.

After you have handled the webhooks, check that the purchased items are in your inventory. That’s all.

Next steps

Need help?
Contact our integration team at [email protected]