Skip to main content
Use this server-side helper to generate a canonical TON message payload and a tracking reference.
import { createTonPayTransfer } from "@ton-pay/api";

const { message, bodyBase64Hash, reference } = await createTonPayTransfer(
  {
    amount: 10.5,
    asset: "TON",
    recipientAddr: "<RECIPIENT_ADDRESS>",
    senderAddr: "<SENDER_ADDRESS>",
    commentToSender: "Payment for Order #1234",
    commentToRecipient: "Order #1234",
  },
  {
    chain: "testnet",
    apiKey: "<TONPAY_API_KEY>",
  }
);
Providing an API key enables transaction visibility in the TON Pay Merchant Dashboard, webhook notifications, and wallet management features.

Function signature

createTonPayTransfer(
  params: CreateTonPayTransferParams,
  options?: APIOptions
): Promise<CreateTonPayTransferResponse>

Transfer parameters

type CreateTonPayTransferParams = {
  amount: number;
  asset: string;
  recipientAddr?: string;
  senderAddr: string;
  queryId?: number;
  commentToSender?: string;
  commentToRecipient?: string;
};

API options

type APIOptions = {
  chain?: "mainnet" | "testnet";
  apiKey?: string;
};
chain
string
default:"mainnet"
Target blockchain network. Use "mainnet" for production or "testnet" for development and testing.
apiKey
string
The TON Pay API key from the Merchant Dashboard. When provided, it enables:
  • Transaction visibility in the TON Pay Merchant Dashboard.
  • Webhook notifications for completed transactions.
  • Receiving wallet management from the Merchant Dashboard.

Parameter details

amount
number
required
Human-readable payment amount. Decimals are allowed, for example, 10.5 TON.
asset
string
required
Asset to transfer. Use “TON” for Toncoin or a jetton master address or constant, for example, USDT.
Mainnet address riskToken constants such as USDT always reference mainnet jetton master addresses and are not affected by the chain option. Using them on testnet may send transactions to mainnet contracts.For testnet, explicitly pass the correct testnet jetton master address instead of using token constants.
recipientAddr
string
Payee wallet address. Optional if an API key is provided. Defaults to the merchant’s default wallet address configured in the Merchant Dashboard.
senderAddr
string
required
Payer wallet address. In UI flows, obtain it from TON Connect.
queryId
number
Jetton only. Numeric identifier embedded into the jetton payload for idempotency and tracking. Ignored for Toncoin payments.
commentToSender
string
Short note visible to the user in the wallet while signing.
Comments are on-chain and publicly visible in blockchain explorers. Do not include confidential data. Keep comments under 120 characters to avoid increased gas fees.
commentToRecipient
string
Note visible to the recipient after the transfer is received.
Comments are on-chain and publicly visible in blockchain explorers. Do not include confidential data. Keep comments under 120 characters to avoid increased gas fees.

Predefined asset constants

Built-in constants can be used instead of raw addresses.
import { createTonPayTransfer, TON, USDT } from "@ton-pay/api";

// Toncoin transfer
await createTonPayTransfer(
  {
    amount: 1,
    asset: TON, // same as "TON"
    recipientAddr: "<RECIPIENT_ADDRESS>", // shortened example; replace with a full wallet address
    senderAddr: "<SENDER_ADDRESS>",       // shortened example; replace with a full wallet address
  },
  {
    chain: "testnet",
    apiKey: "<TONPAY_API_KEY>", // optional
  }
);

// USDT jetton transfer
await createTonPayTransfer(
  {
    amount: 25,
    asset: USDT, // mainnet USDT jetton master address
    recipientAddr: "<RECIPIENT_ADDRESS>", // shortened example; replace with a full wallet address
    senderAddr: "<SENDER_ADDRESS>",       // shortened example; replace with a full wallet address
  },
  {
    chain: "testnet",
    apiKey: "<TONPAY_API_KEY>",
  }
);
Mainnet address riskIn asset, token constants such as USDT always reference mainnet jetton master addresses and are not affected by the chain option. Using them on testnet may send transactions to mainnet contracts.For testnet, explicitly pass the correct testnet jetton master address instead of using token constants.
Response:
type CreateTonPayTransferResponse = {
  message: {
    address: string;
    amount: string;
    payload: string;
  };
  bodyBase64Hash: string;
  reference: string;
};

Response fields

message
object
required
Prebuilt TON Connect transaction message. Intended to be passed to sendTransaction as messages: [message].
bodyBase64Hash
string
required
Base64 hash of the signed message body content (payload). Used with getTonPayTransferByBodyHash.
reference
string
required
Tracking reference string. Used with getTonPayTransferByReference.
The SDK call returns a ready-to-send message along with identifiers for subsequent status lookups. Always persist tracking identifiers server-side before sending the transaction to the user.

API key configuration

The TON Pay API key is optional in development and recommended for production. When configured, it enables transaction tracking, webhook notifications, and centralized wallet management in the TON Pay Merchant Dashboard.

Obtain an API key

1

Open the Merchant Dashboard

Open the TON Pay Merchant Dashboard and sign in to the merchant account.
2

Open Developer settings

Navigate to DeveloperAPI Keys sections.
3

Generate or copy an API key

Generate a new API key or copy an existing one and store it securely.

Usage in code

import { createTonPayTransfer } from "@ton-pay/api";

const { message, reference, bodyBase64Hash } = await createTonPayTransfer(
  {
    amount: 10.5,
    asset: "TON",
    // recipientAddr is optional when API key is provided
    // Will use merchant's default wallet from the Merchant Dashboard
    senderAddr: userWalletAddress,
  },
  {
    chain: "testnet",
    apiKey: "<TONPAY_API_KEY>",
  }
);

API key capabilities

CapabilityWith API keyWithout API key
Transaction visibility and monitoringTransfers appear in the TON Pay Merchant Dashboard with status tracking and full transaction history.Transfers are processed on-chain but are not visible in the Merchant dashboard.
Webhook notificationsReal-time HTTP POST notifications are sent for completed and failed payments.No webhook notifications; payment status must be obtained through the manual polling.
Receiving wallet managementReceiving wallets are managed from the TON Pay Merchant Dashboard; addresses can be updated without code changes.Receiving wallet addresses must be hard-coded in the application.
recipientAddr handlingOptional; when omitted, the merchant’s default wallet from the Merchant Dashboard is used automatically.Required for every transfer.
With API key: recipientAddr is optional.
const result = await createTonPayTransfer(
  {
    amount: 10,
    asset: "TON",
    senderAddr: "<SENDER_ADDRESS>",
  },
  {
    chain: "testnet",
    apiKey: "<TONPAY_API_KEY>",
  }
);
Without API key: recipientAddr is required.
// Works without API key - transaction processes normally
const result = await createTonPayTransfer(
{
  amount: 10,
  asset: "TON",
  recipientAddr: "<RECIPIENT_ADDRESS>",
  senderAddr: "<SENDER_ADDRESS>",
},
{ chain: "testnet" } // No apiKey - transaction works but no dashboard features
);

Testnet configuration

Funds at riskRunning tests on mainnet can result in irreversible loss of real TON. Always use chain: "testnet" and testnet wallet addresses during development. Verify the network before switching to mainnet.

Set up testnet

1

Set chain to testnet

Configure the chain option to "testnet" in the API calls:
const { message, reference, bodyBase64Hash } = await createTonPayTransfer(
{
  amount: 5.0,
  asset: "TON",
  recipientAddr: "<RECIPIENT_ADDRESS>",
  senderAddr: "<SENDER_ADDRESS>",
},
{
  chain: "testnet", // Use testnet
  apiKey: "<TONPAY_API_KEY>",
}
);
2

Use testnet wallet addresses

Ensure all wallet addresses are valid testnet addresses.
3

Obtain testnet TON

4

Configure testnet jettons

If testing with jettons, use the correct testnet jetton master addresses; not mainnet addresses.
// Example: Testnet USDT (use actual testnet address)
await createTonPayTransfer(
{
  amount: 10,
  asset: "<TESTNET_USDT_MASTER_ADDRESS>", // Testnet jetton address
  recipientAddr: "<RECIPIENT_ADDRESS>",
  senderAddr: "<SENDER_ADDRESS>",
},
{ chain: "testnet" }
);

Configure environment

Use environment variables to switch between mainnet and testnet:
// .env.development
TON_CHAIN=testnet
MERCHANT_WALLET_ADDRESS=EQC...TESTNET_ADDRESS

// .env.production
TON_CHAIN=mainnet
MERCHANT_WALLET_ADDRESS=EQC...MAINNET_ADDRESS
// In the application code
const { message, reference, bodyBase64Hash } = await createTonPayTransfer(
  {
    amount: orderAmount,
    asset: "TON",
    recipientAddr: "<WALLET_ADDRESS>",
    senderAddr: "<CUSTOMER_WALLET_ADDRESS>",
  },
  {
    chain: "testnet",
    apiKey: "<TONPAY_API_KEY>",
  }
);

Verify testnet transactions

Verify testnet transactions using testnet block explorers:
// Replace txHash with the actual transaction hash.
// After transaction completes:
console.log(`View on explorer: https://testnet.tonscan.org/tx/${txHash}`);

Apply testing best practices

  • Test all payment outcomes on testnet, including success, failures, user rejections, and edge cases.
  • Verify webhook endpoint correctly processes testnet webhooks; payload structure matches mainnet.
  • Validate behavior across different amounts, including small, large, and fractional values.
  • Ensure reference and bodyBase64Hash are persisted and usable for status lookups.
  • Exercise error paths such as insufficient balance, invalid addresses, and network issues.