apiton blog
Reading a TON address: raw vs bounceable vs non-bounceable
Copy the same wallet from three TON apps and you may get three different-looking strings. They are usually the same account. This article decodes the formats defined in TEP-2 so you can tell them apart at a glance.
One address, four spellings
Here is the TON DNS root contract (the collection that holds every .ton domain) in each form:
| Form | Value |
|---|---|
| raw | 0:b774d95eb20543f186c06b371ab88ad704f7e256130caf96189368a7d0cb6ccf |
| bounceable (mainnet) | EQC3dNlesgVD8YbAazcauIrXBPfiVhMMr5YYk2in0Mtsz0Bz |
| non-bounceable (mainnet) | UQC3dNlesgVD8YbAazcauIrXBPfiVhMMr5YYk2in0Mtszx22 |
| bounceable (testnet) | kQC3dNlesgVD8YbAazcauIrXBPfiVhMMr5YYk2in0Mtsz_v5 |
All four identify the same account.
The raw form
An account is identified by two numbers:
- the workchain —
0for the basechain where almost everything lives,-1for the masterchain; - the account id — a 256-bit hash of the contract's initial code and data.
The raw form writes them as workchain:hex, e.g. 0:b774…6ccf. It is exact and unambiguous, but
it has no checksum, so a typo produces another valid-looking address.
The user-friendly form
The friendly form packs 36 bytes and encodes them as 48 characters of URL-safe base64:
| Bytes | Content |
|---|---|
| 1 | flags: 0x11 bounceable, 0x51 non-bounceable, +0x80 for testnet |
| 1 | workchain (0x00 for 0, 0xff for -1) |
| 32 | account id |
| 2 | CRC16-XMODEM checksum of the first 34 bytes |
The first byte is why mainnet friendly addresses start with EQ (bounceable, 0x11) or
UQ (non-bounceable, 0x51), and testnet ones with kQ or 0Q. The checksum
catches typos: a wallet app rejects a friendly address whose CRC does not match. Some tools use
the standard base64 alphabet (+ and /) instead of the URL-safe one (- and _); both decode
to the same bytes.
What "bounceable" means
The flag is not a property of the account — it is a hint to the sender:
- Bounceable (
EQ…). If the message fails at the destination (for example, the contract throws, or the account is not deployed), the remaining value bounces back to the sender. Use it for smart contracts: jetton masters, NFT items, sale contracts, DNS items. - Non-bounceable (
UQ…). The value stays at the destination even if nothing runs there. This is the right choice for wallets, including brand-new ones that have not been deployed yet — a bounceable transfer to an undeployed wallet would simply come back.
Most wallet apps now show user wallets as UQ… by default. The apiton API follows the same
rule and returns addresses in non-bounceable form (UQ…) unless a field says otherwise; it
accepts any of the forms as input, and a name.ton domain on methods that resolve DNS.
Practical rules
- Comparing addresses? Convert both to raw (or to the same friendly flag) first.
EQ…andUQ…of the same account differ in the first characters and the last ones, because the checksum changes with the flag. - Sending to a person? Use their
UQ…wallet address. - Sending to a contract?
EQ…is safer: a failed call returns your funds. - Seeing
kQ…or0Q…? That is a testnet address. Mainnet services (including apiton in production) do not accept it.
Checking an address
Paste any form into @apitonBot: it shows the balance, the contract type (wallet version, jetton wallet, NFT item, DNS item…), recent transactions and the NFTs it holds, and you can watch it for new transactions. On apiton.org, usernames, numbers and domains show their owner wallet — for example the +888 0000 1312 page — and the lists of usernames for sale and expired domains are a quick way to see real owner addresses.