Skip to main content

Payment API

Payment API

TudadaSDK.payment.* is the payment API for purchasing in-game products. The game requests purchases by productId alone, without needing to know the payment method or rail. Payment method selection, price calculation, receipt verification, and grant processing are all handled by the Tudada platform.

Each action is split into a callback version (getProducts, etc. — success / fail / complete callbacks, returns nothing) and an *Async version (getProductsAsync, etc. — returns a Promise). The callback success value is identical to the resolve value of the corresponding *Async, and the required arguments of *Async are passed as positional arguments.

Availability & showing the store
  • Payment unsupportedgetProductsAsync() rejects with PAYMENT_UNAVAILABLE (the callback version getProducts() invokes fail).
  • Supported, no matching products — returns an empty array (a normal response). If empty, do not show the store UI.
  • Communication failure — rejects with NETWORK_ERROR.
Final grant confirmation on the server

The result of purchase() is reduced information for display and UX. Confirm the final grant on your game server. The transaction does not include amount or receipt; authoritative grant information is held by your game server and the Tudada server.

payment.getProducts(options?)

Retrieves the list of purchasable products (callback version, returns nothing).

Options:

ParameterTypeRequiredDescription
successfunction-Success callback — PaymentProduct[]
failfunction-Failure callback — PaymentFailResult
completefunction-Completion callback
TudadaSDK.payment.getProducts({
success: (products) => {
if (products.length === 0) hideStore(); // empty array → do not show the store
else renderStore(products);
},
fail: (err) => console.warn('Product lookup failed:', err.code),
});

payment.getProductsAsync()

Promise version of getProducts(). Returns Promise<PaymentProduct[]>, which is an empty array if there are no products available for sale.

const products = await TudadaSDK.payment.getProductsAsync();
if (products.length === 0) {
hideStore(); // empty array → do not show the store
} else {
renderStore(products);
}

payment.getProduct(options)

Retrieves a single product (callback version). If the product does not exist or is not for sale, PRODUCT_NOT_FOUND is passed to the fail callback.

Options:

ParameterTypeRequiredDescription
productIdstringID of the product to retrieve
successfunction-Success callback — PaymentProduct
failfunction-Failure callback
completefunction-Completion callback
TudadaSDK.payment.getProduct({
productId: 'coin_100',
success: (product) => console.log(product.name, product.price),
fail: (err) => {
if (err.code === 'PRODUCT_NOT_FOUND') showToast('This product is not for sale.');
},
});

payment.getProductAsync(productId)

Promise version of getProduct(). Takes productId as a positional argument and returns Promise<PaymentProduct>, rejecting with PRODUCT_NOT_FOUND if the product does not exist or is not for sale.

try {
const product = await TudadaSDK.payment.getProductAsync('coin_100');
console.log(product.name, product.price);
} catch (err) {
if (err.code === 'PRODUCT_NOT_FOUND') showToast('This product is not for sale.');
}

payment.purchase(options)

Purchases a product (callback version). On success, the transaction is delivered with a GRANTED (grant complete) or PENDING (accepted, awaiting confirmation) status; otherwise the fail callback is invoked.

Options:

ParameterTypeRequiredDescription
productIdstringID of the product to purchase
passthroughPayloadstring-Opaque echo string (≤1000 UTF-8 bytes). Returned verbatim during purchase verification. No secrets or personal data
successfunction-Success callback — PaymentTransaction
failfunction-Failure callback
completefunction-Completion callback
TudadaSDK.payment.purchase({
productId: 'coin_100',
passthroughPayload: 'order-1234', // optional — returned verbatim on verification
success: (txn) => {
if (txn.status === 'GRANTED') {
// Grant complete — reflect in UX (final confirmation on the game server)
} else if (txn.status === 'PENDING') {
// Accepted — awaiting confirmation. Check later status with getTransaction
}
},
fail: (err) => {
if (err.code === 'USER_CANCELLED') return; // user closed the payment window
console.error('Payment failed:', err.code);
},
});

payment.purchaseAsync(productId, passthroughPayload?)

Promise version of purchase(). Takes productId (required) and passthroughPayload (optional) as positional arguments and returns Promise<PaymentTransaction> (GRANTED / PENDING).

try {
const txn = await TudadaSDK.payment.purchaseAsync('coin_100', 'order-1234');

if (txn.status === 'GRANTED') {
// Grant complete — reflect in UX (final confirmation on the game server)
} else if (txn.status === 'PENDING') {
// Accepted — awaiting confirmation. Check later status with getTransactionAsync
}
} catch (err) {
if (err.code === 'USER_CANCELLED') return; // user closed the payment window
console.error('Payment failed:', err.code);
}

payment.getTransaction(options)

Retrieves a transaction's status and result (callback version). Use it for follow-up checks when purchase ended in PENDING, etc. If the transaction does not exist or is not owned by the user, TRANSACTION_NOT_FOUND is passed to the fail callback.

Options:

ParameterTypeRequiredDescription
txnKeystringKey of the transaction to retrieve
successfunction-Success callback — PaymentTransaction
failfunction-Failure callback
completefunction-Completion callback
TudadaSDK.payment.getTransaction({
txnKey: prevTxn.txnKey,
success: (txn) => console.log(txn.status),
});

payment.getTransactionAsync(txnKey)

Promise version of getTransaction(). Takes txnKey as a positional argument and returns Promise<PaymentTransaction> (any of the 5 statuses possible), rejecting with TRANSACTION_NOT_FOUND if the transaction does not exist or is not owned by the user.

const txn = await TudadaSDK.payment.getTransactionAsync(prevTxn.txnKey);
console.log(txn.status); // 'PENDING' | 'GRANTED' | 'FAILED' | 'PARTIALLY_REFUNDED' | 'REFUNDED'

Data Types

PaymentProduct

FieldTypeDescription
productIdstringMarket-agnostic single product ID (specified at purchase)
namestringRegistered product name
pricestringCurrent price (with any discount applied) — display-ready string (e.g. "4,400", "4.99"). No arithmetic, display as-is
currencystringCurrency identifier string (e.g. "KRW"). Display unrecognized values as the raw string
originalPricestring?Pre-discount price (display-ready string). For strikethrough display, etc.
discountRatestring?Discount rate display string (e.g. "20%"). Marketing label — do not back-calculate from price

All prices are display-ready completed strings. Thousands separators and decimal places are already applied, so output them as-is and do not use them in direct calculations.

PaymentTransaction

A reduced view for verification and UX (no amount or receipt).

FieldTypeDescription
txnKeystringUnique key — used for re-querying
statusstringTransaction status (see table below)
productIdstringProduct of the transaction
failReasonstring | nullDetailed reason for diagnostics and logging (do not show to users, value subject to change). null if none
passthroughPayloadstring | nullThe value passed at purchase, verbatim. null if omitted or an empty string
requestedAtnumberRequest time (Unix epoch ms)
grantedAtnumber | nullTime of first grant (epoch ms). null if not yet granted

Transaction status (status):

ValueDescription
PENDINGAccepted, grant not yet confirmed
GRANTEDGrant complete
FAILEDFailed
PARTIALLY_REFUNDEDPartially refunded (a past grant exists)
REFUNDEDRefunded (a past grant exists)

purchase only resolves with GRANTED / PENDING, while getTransaction may return any of the 5 statuses.

Error Handling

Failures are delivered via the fail callback (callback version) or Promise reject (*Async version), and branching is always done by code.

FieldTypeDescription
codestringError code (see table below) — basis for branching
errMsgstringMessage (do not show to users)
txnKeystring?Present only on failures where a transaction was recorded
failReasonstring?Detailed reason for diagnostics and logging

Error codes (code):

CodeDescription
PAYMENT_UNAVAILABLEEnvironment where payment is unavailable
USER_CANCELLEDUser closed the payment window
PAYMENT_FAILEDPayment failed (card declined, insufficient balance, etc.)
PRODUCT_NOT_FOUNDUnregistered productId
INVALID_PARAMInvalid argument (passthroughPayload exceeded, etc.)
PURCHASE_REJECTEDVerification/grant rejected
PAYMENT_IN_PROGRESSA purchase is in progress, so the new call is rejected (one concurrent purchase)
TRANSACTION_NOT_FOUNDTransaction does not exist or is not owned
SESSION_EXPIREDSession expired — re-login required
NETWORK_ERRORCommunication failure
try {
await TudadaSDK.payment.purchaseAsync('coin_100');
} catch (err) {
switch (err.code) {
case 'USER_CANCELLED': break; // silently ignore
case 'PAYMENT_IN_PROGRESS': showToast('Processing.'); break;
case 'SESSION_EXPIRED': requestRelogin(); break;
default: showToast('Payment failed.');
}
}