How to Set Up TON Payment Acceptance: TON Connect, Jetton, Automation

TON is not Ethereum with a different RPC. The asynchronous transaction model and tree-like message structure break developer intuition. When a user sends native TON to your address, it's a single transaction. When they send Jetton (USDT on TON), it's a chain of three: transfer → internal message → n

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1450
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1308
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1003
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1269
  • image_logo-advance_0.webp
    B2B Advance company logo design
    717
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1008

TON is not Ethereum with a different RPC. The asynchronous transaction model and tree-like message structure break developer intuition. When a user sends native TON to your address, it's a single transaction. When they send Jetton (USDT on TON), it's a chain of three: transfer → internal message → notification. A monitoring error leads to lost payments and headache with refunds.

Recently, a project with 5000 daily Jetton payments approached us. After auditing their system, we found they weren't accounting for bounced transactions, causing 2% of payments to be credited erroneously. We rebuilt the architecture with unique addresses and Gasless relays, cutting losses to zero. We set up payment acceptance turnkey: contact us, and we'll assess your project and choose the optimal architecture in one day.

How to Accept Native TON and Jetton

Native TON

Generate a unique address or use a single address with a comment (memo) for identification. Monitor via TON Center API or TonAPI:

import { TonClient } from '@ton/ton'; import { Address } from '@ton/core'; const client = new TonClient({ endpoint: 'https://toncenter.com/api/v2/jsonRPC', apiKey: process.env.TONCENTER_API_KEY, }); async function checkIncomingTransactions( address: string, lastLt: string // last known logical time ) { const addr = Address.parse(address); const transactions = await client.getTransactions(addr, { limit: 20, lt: lastLt, archival: false, }); for (const tx of transactions) { // Only incoming, not bounce if (tx.inMessage && tx.inMessage.info.type === 'internal') { const info = tx.inMessage.info; const value = info.value.coins; // in nanoTON const comment = tx.inMessage.body; // text comment // Match comment with our payment ID console.log(`Received: ${value} nanoTON, comment: ${comment}`); } } } 

Important: check the bounce flag and bounced flag. A bounced transaction means a return—do not count it.

Jetton (USDT, USDC, NOT)

Jetton Transfer is more complex: the user sends a message to their JettonWallet, which sends an internal message to the recipient's contract, which then sends a transfer_notification to the recipient's address. In forward_ton_amount, we include the fee for the notification; in forward_payload, we include the payment ID:

transfer_notification#7362d09c query_id: uint64 amount: coins // amount of Jetton sender: MsgAddress // sender's address forward_payload: ^Cell // our custom payload (payment ID) 

Monitor not the main address, but the JettonWallet of our address:

// Get our JettonWallet address for USDT async function getJettonWalletAddress( ownerAddress: string, jettonMasterAddress: string ): Promise<string> { const master = client.open( JettonMaster.create(Address.parse(jettonMasterAddress)) ); const walletAddr = await master.getWalletAddress( Address.parse(ownerAddress) ); return walletAddr.toString(); } // USDT on TON mainnet const USDT_MASTER = 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs'; 

What to Choose: Unique Addresses or Comment?

Characteristic Comment (memo) Unique Address
Implementation complexity Low Medium (HD wallet)
User errors 1-3% forget comment 0%
Fund sweeping Not required Required sweep
Monitoring One address Many addresses
Recommendation Up to 100 payments/day From 1000 payments/day

Comment/Memo Identification

One address, user specifies comment (payment ID). Simple, but requires UX—explain the need for a comment. Error = lost payment (needs manual reconciliation).

Unique Address per Payment

Generate HD wallet (BIP39 + non-standard derivation). Each order gets a separate address. No comments, no errors, simple monitoring:

import { mnemonicToPrivateKey } from '@ton/crypto'; import { WalletContractV4 } from '@ton/ton'; async function derivePaymentAddress( masterMnemonic: string[], orderIndex: number ): Promise<string> { const keyPair = await mnemonicToPrivateKey(masterMnemonic); const wallet = WalletContractV4.create({ publicKey: keyPair.publicKey, workchain: 0, walletId: 698983191 + orderIndex, // unique subwalletId }); return wallet.address.toString({ bounceable: false }); } 

Downside: need to sweep funds to a main address.

Polling or Webhook?

Method Latency Load Complexity
Polling (TON Center) ~5-30 sec Medium Low
Webhook (TON Center) ~1-2 sec Low Medium
WebSocket (TonAPI) ~0.5 sec Low High
Own node ~0 sec Very high Very high

For production, use TonAPI + WebSocket with polling fallback. A self-hosted node is justified for millions of transactions per day. Webhook is 10x faster than polling.

Gasless and Bounce: Common Problems

Gasless

Gasless allows users to pay without a TON balance for fees. This is critical for Jetton payments: to send USDT, you need TON for gas. The service covers the fee via a relay. Set up a relay via TON Connect or a relay contract. Gasless increases conversion by 15-30% in mobile apps.

Bounce

If you don't filter bounced transactions, you may credit a payment that never arrived. In TON, bounces are normal: the recipient contract may reject the message. Check the bounced flag in the message body. For Jetton, also track transfer_notification—its absence is also a sign of failure.

Steps to Set Up TON Payment Acceptance

  1. Analysis—assess load, asset types (TON, Jetton), choose architecture.
  2. Choose identification method—comment or unique addresses.
  3. Develop monitoring—integrate with TON Center / TonAPI, handle webhook/WebSocket.
  4. Integrate with backend—map transactions to orders, handle errors.
  5. Test on testnet—use a bot to distribute test TON and Sandbox from Blueprint.
  6. Deploy—set up production environment, monitoring, and alerts.

What's Included in the Work

  • Architecture documentation—detailed design of payment flow.
  • Access to test environment—testnet endpoints and credentials.
  • Monitoring setup—alerts for bounced transactions and failures.
  • Training session—one-hour walkthrough for your team.
  • Support for 30 days after deployment.

Our Company Metrics

  • 5+ years in blockchain development.
  • 50+ projects delivered, including 10+ TON integrations.
  • 99.9% uptime for payment systems.

Timelines and Cost

Basic setup takes 2–4 weeks. Costs start from $5,000 for a simple setup with one asset and comment-based identification. Gasless relay and multi-asset support increase the budget. Get a free project assessment—contact us today.

Common Mistakes in TON Payment Acceptance

  • Ignoring bounced transactions—crediting failed payments.
  • Monitoring the main address instead of JettonWallet—missing Jetton payments.
  • Using only polling without fallback—losing transactions under high load.
  • Not testing on testnet—production errors.
  • Not accounting for asynchronicity—trying to wait synchronously for a contract response.

Testing and Deployment

Testnet: use a bot to distribute test TON. API endpoint https://testnet.toncenter.com/api/v2/jsonRPC. For local development, use Sandbox from Blueprint: a TVM emulator without network. The asynchronous message model requires special testing. Order TON payment acceptance setup to eliminate monitoring errors and automate accounting.

References: TON Documentation, TON Center API, TonAPI, Blueprint Sandbox