What accepting TON payments actually involves
"Accept TON payments" sounds like a single feature. In practice it's four separate problems, and most of the friction in doing this yourself comes from treating it as one. Solve these four and you have a working integration, whether you build it or buy it:
- A wallet you control. Somewhere the money actually lands — an address only you hold the keys to, not an intermediary's pooled account.
- A way to tell payments apart. The TON network sees a transfer of a certain amount to a certain address. It has no idea which of your customers sent it or which order it's for, unless you attach something that says so.
- Detection on-chain. Something has to watch the chain and notice when a matching payment shows up — the network doesn't push notifications to you.
- Confirmation back to your system. Once a payment is detected, your order/booking/subscription system needs to hear about it and act — mark the order paid, unlock the download, ship the item.
Everything below is one way to solve each of the four — either by hand, or with a gateway that has already solved them.
How TON payments actually get matched to an order
Problem two above — telling payments apart — has a standard answer on TON: the memo. When you create an invoice, it's issued a short, unique code (Zyrvix uses seven characters). That code has to travel with the payment, and TON transfers have a native place to carry it — the comment field, which every wallet exposes when sending. The payer isn't asked to do anything unusual; the code shows up automatically, filled in for them by the QR code or payment link they used to pay.
From the merchant's side, the sequence looks like this:
- An invoice is created. Your system generates a wallet address to receive the payment and a unique memo for this specific order — the equivalent of a reference number on a bank transfer.
- The customer pays, memo included. They send the exact amount to that address, with the memo attached as the transaction comment — usually done for them automatically when they scan a QR code or tap a payment link.
- The chain is watched for a match. Something on your side polls or subscribes to activity on that address, looking for an incoming transfer whose comment matches an open invoice's memo.
- Your system is told. The moment a match is confirmed on-chain, your backend is notified — no manual reconciliation, no customer support ticket asking "did you get my payment?"
That's the entire mechanism. There's no account debit, no card network, no clearing house — just a public ledger, a code that ties a transfer to an order, and something watching for it.
Build it yourself, or use a gateway
Nothing above is secret, and nothing stops you from building it. A reasonable DIY sketch looks like this: poll a TON API for transactions to your wallet, parse each one for the amount and comment, and match it against your own table of open invoices. Then handle the cases that don't show up in the happy-path description:
- What happens if nobody pays — how long do you wait before the invoice is considered dead, and what state does it move to?
- What happens on a partial payment — do you accept it, top it up, or leave it pending?
- What happens on an overpayment — refund the difference, credit it, or resolve automatically?
- How do you notify the rest of your stack once a payment lands, and what retries that notification if the first attempt fails?
- How do you keep your own database honest against reorgs, dropped connections, and API rate limits, given the chain is the only source of truth?
None of this is hard in isolation. It's tedious in aggregate, and it's exactly the kind of infrastructure that's cheap to get 90% right and expensive to get the last 10% right — the edge cases are where support tickets and lost payments come from. A payment gateway's job is to have already built and hardened this layer, so "accept TON payments" collapses back down to a single API call and a webhook.
For the specific answers, on Zyrvix: an invoice that receives more than it asked for resolves automatically as paid — there's no separate refund-the-difference step to build. An invoice that receives less lands in an underpaid status instead of being silently accepted or left pending indefinitely; the merchant then decides whether to accept that partial amount, through the same manual reconciliation call that also handles a payment arriving after an invoice has already expired. Full detail on that endpoint is in the docs.
What "non-custodial" means, specifically
Zyrvix sits on the "use a gateway" side of that choice, with one property worth stating plainly before anything else: it is non-custodial. The wallet address on every invoice is your own registered wallet — the one from problem one above, the one only you hold the keys to. When a customer pays, the funds move directly from their wallet to yours, on-chain, in one transaction. There is no intermediate holding account and no payout step, because the money was never anywhere else to pay out from.
The gateway's job, in this model, is narrower than it sounds: watch the chain, match payments to invoices by memo, and tell your system what happened. It never has custody of the funds at any point, which also means it's never in a position to delay, gate, or freeze a payout — there isn't one. For the full comparison against custodial processors, where the money does pass through a third party first, see custodial vs non-custodial crypto payment gateways.
Step by step with Zyrvix
Concretely, going from zero to a working integration looks like this:
- Register an account. Email verification is required before the account exists — this keeps registration itself free of spam without gating it behind manual approval.
- Add your payout wallet. Register the TON address you want to receive payments at, and set it as your default so you can omit it from individual invoice requests.
- Create an invoice from your backend. One authenticated API call — an amount and an expiry window are all that's required:
# replace with the full sk_ key you saved at creationcurl -X POST https://api.zyrvix.com/invoices \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-H "Idempotency-Key: $(uuidgen)" \-d '{"amount": "5.5","pay_to_address": "EQD_YOUR_TON_WALLET_ADDRESS","expires_in_seconds": 1200}'
The response includes a hosted_payment_url — redirect your customer there and Zyrvix renders the QR code, the wallet address, the memo, and a countdown to expiry. You can also build your own payment UI from the raw pay_to_address and memo fields if you'd rather not use the hosted page at all.
- The customer pays from whatever TON wallet they already have, scanning the QR code or tapping the deep link — the memo is attached for them automatically.
- An
invoice.paidwebhook confirms it. The moment the payment is matched on-chain, your configured webhook URL receives a signed event and your backend can complete the order — no polling required.
Full request/response detail, authentication, idempotency, and webhook signature verification all live in the quick start section of the docs.
Questions merchants actually ask
What does it cost? There's an invoice fee and a small monthly base fee, both charged in TON — no fixed numbers here since rates are configurable; see current pricing for the live figures, or what that fee actually costs you in practice once canceled and expired invoices are factored in.
How do customers actually pay? With whatever TON wallet they already use — most commonly Tonkeeper or Telegram's built-in wallet. Neither requires the customer to install anything unfamiliar if they're already transacting in TON.
Do you convert to fiat for me? No, by design — this is the direct consequence of being non-custodial. You receive TON and hold TON; there's no conversion step and nothing to hold your funds while a conversion happens.