From c7729b0ad39cd94731be81094ddd6ce1df925a71 Mon Sep 17 00:00:00 2001
From: Antonoff <35700168+memearchivarius@users.noreply.github.com>
Date: Wed, 25 Feb 2026 14:46:38 +0300
Subject: [PATCH 01/10] draft
---
docs.json | 1 +
ecosystem/ton-connect/message-lookup.mdx | 4 ++
foundations/messages/external-in.mdx | 2 +
foundations/messages/normalized-hash.mdx | 88 ++++++++++++++++++++++++
4 files changed, 95 insertions(+)
create mode 100644 foundations/messages/normalized-hash.mdx
diff --git a/docs.json b/docs.json
index b66444d4a..f86dc3ed9 100644
--- a/docs.json
+++ b/docs.json
@@ -592,6 +592,7 @@
"foundations/messages/overview",
"foundations/messages/internal",
"foundations/messages/external-in",
+ "foundations/messages/normalized-hash",
"foundations/messages/external-out",
"foundations/messages/deploy",
"foundations/messages/modes",
diff --git a/ecosystem/ton-connect/message-lookup.mdx b/ecosystem/ton-connect/message-lookup.mdx
index 05849ac9d..2a6a22ffb 100644
--- a/ecosystem/ton-connect/message-lookup.mdx
+++ b/ecosystem/ton-connect/message-lookup.mdx
@@ -29,6 +29,10 @@ The normalized hash is computed by applying the following standardization rules
1. **InitState (`init`)**: set to an empty value
1. **Body**: always stored as a reference
+
+ For more details on the standardization process, language-agnostic implementations, and uniqueness constraints, see the [Normalized message hash](/foundations/messages/normalized-hash) documentation.
+
+
## Transaction lookup using external message from TON Connect
```ts
diff --git a/foundations/messages/external-in.mdx b/foundations/messages/external-in.mdx
index f3a7b2e6a..9b1ae2cb8 100644
--- a/foundations/messages/external-in.mdx
+++ b/foundations/messages/external-in.mdx
@@ -42,3 +42,5 @@ Incoming external messages are sent to the contract from outside the blockchain,
## Multiple delivery
When an incoming external message is sent to the blockchain, validators share them with each other, and might accidentally (or intentionally) deliver it several times. As it's usually preferred to process a unique incoming external message only once, some measures need to be taken to ensure duplicate messages are not accepted. Some of these techniques can be found in [wallet](/standard/wallets/comparison) contracts.
+
+For reliable off-chain transaction tracking, the ecosystem relies on the [normalized message hash](/foundations/messages/normalized-hash) standard.
diff --git a/foundations/messages/normalized-hash.mdx b/foundations/messages/normalized-hash.mdx
new file mode 100644
index 000000000..997912293
--- /dev/null
+++ b/foundations/messages/normalized-hash.mdx
@@ -0,0 +1,88 @@
+---
+title: "Normalized message hash"
+sidebarTitle: "Normalized hash"
+---
+
+import { Aside } from "/snippets/aside.jsx";
+
+The normalized message hash is a consistent and reliable identifier for [external-in](/foundations/messages/external-in) messages. It remains constant regardless of variations in the `src`, `import_fee`, and `init` fields, which can change without affecting the validity of the message. This hash is particularly useful for tracking transactions.
+
+
+ For the canonical specification, refer to [TEP-467: Normalized Message Hash](https://github.com/ton-blockchain/TEPs/blob/master/text/0467-normalized-message-hash.md).
+
+
+## Why normalization is needed
+
+In TON, an external-in message can be constructed and packed in different ways that are all logically identical. Fields such as the source address (`src`), the `import_fee`, and the state initialization (`init`) can vary depending on the sender's implementation or the API provider processing the message.
+
+Because these non-essential fields are included when computing the standard cell hash, functionally identical messages can produce different message hashes. This variability complicates reliable transaction tracking and deduplication, as highlighted in the [TON Console transaction tracking guide](https://docs.tonconsole.com/academy/transaction-tracking).
+
+By applying normalization rules before calculating the hash, the variable fields are removed or zeroed out, ensuring that the same logical message always produces the exact same hash.
+
+## Calculate the normalized hash
+
+The normalized hash is computed by standardizing the `ext_in_msg_info$10` fields before serializing the message. This approach is independent of any specific SDK and can be implemented in any language.
+
+According to TEP-467, apply the following rules:
+
+1. **Source Address (`src`)**: Set to `addr_none$00`.
+2. **Import Fee (`import_fee`)**: Set to `0`.
+3. **InitState (`init`)**: Set to `nothing$0`.
+4. **Body (`body:(Either X ^X)`)**: Always store as a reference (`^X`). The content of the body itself is included without modification.
+
+After constructing the cell with these standardized values, calculate its standard [cell hash](/foundations/serialization/cells) (the SHA-256 of the root cell).
+
+### Low-level construction example
+
+The following TypeScript example demonstrates the raw cell construction. This logic illustrates the underlying TL-B serialization and can be adapted to any programming language or SDK.
+
+```typescript
+import { beginCell, Cell, Address } from "@ton/core";
+
+function normalizeExternalMessage(destAddress: Address, bodyCell: Cell): Cell {
+ return beginCell()
+ .storeUint(0b10, 2) // external-in message prefix
+ .storeUint(0b00, 2) // src: addr_none$00
+ .storeAddress(destAddress) // dest: MsgAddressInt
+ .storeCoins(0) // import_fee: 0
+ .storeBit(false) // init: nothing$0
+ .storeBit(true) // body: stored as a reference (^X)
+ .storeRef(bodyCell) // The actual body cell
+ .endCell();
+}
+
+// Compute the standard cell hash
+const normalizedExtMessage = normalizeExternalMessage(destAddress, bodyCell);
+const normalizedHash = normalizedExtMessage.hash().toString("hex");
+```
+
+## Tools and SDK support
+
+Many tools and libraries in the TON ecosystem support the normalized message hash either natively or through API integration.
+
+| Tool | Support | Details |
+|------|---------|---------|
+| **ton/ton** (`@ton/ton`) | Yes | Use `storeMessage(..., { forceRef: true })` and custom logic to clear fields. See [Message lookup](/ecosystem/ton-connect/message-lookup) for an example. |
+| **TonCenter** | Yes | API methods such as `sendBocReturnHash` return the normalized hash; transaction lookups support it. |
+| **TonAPI** | Yes | [Transaction tracking](https://docs.tonconsole.com/tonapi/cookbook/transaction-tracking) and API lookups natively use the normalized hash. |
+| **Tongo** | Yes | The first implementation of the standard ([tonkeeper/tongo#313](https://github.com/tonkeeper/tongo/pull/313)). |
+| **ton-blockchain/ton** | Yes | Supported at the node level ([ton-blockchain/ton#1557](https://github.com/ton-blockchain/ton/pull/1557)). |
+
+
+ For a practical guide on searching for transactions using TON Connect and the normalized hash, see the [Message lookup](/ecosystem/ton-connect/message-lookup) guide.
+
+
+## Uniqueness constraints
+
+The normalized message hash is **not** a globally unique identifier across the entire blockchain. It is possible for custom smart contracts to process identical external messages that produce the same normalized hash, resulting in multiple distinct transaction chains.
+
+However, the normalized message hash serves as a unique identifier for a specific transaction trace when the following conditions are met:
+
+- The message is sent to a [wallet contract](/standard/wallets/comparison).
+- The message includes an instruction to send an internal message with the `IGNORE_ERRORS=+2` flag (this is standard behavior for [TON Connect](/ecosystem/ton-connect/overview) and for wallets starting from v5).
+- The wallet contract is never deleted.
+
+
+ For dApps interacting with user wallets via TON Connect, or for exchanges controlling their outbound external messages, it is safe to reference traces using the normalized hash. This applies even before the transactions are finalized.
+
+
From 143f78753d0a8e535054021fe9fc7431f39aa904 Mon Sep 17 00:00:00 2001
From: Antonoff <35700168+memearchivarius@users.noreply.github.com>
Date: Thu, 26 Feb 2026 19:37:19 +0300
Subject: [PATCH 02/10] Update normalized-hash.mdx
---
foundations/messages/normalized-hash.mdx | 1 -
1 file changed, 1 deletion(-)
diff --git a/foundations/messages/normalized-hash.mdx b/foundations/messages/normalized-hash.mdx
index 997912293..0aec046a8 100644
--- a/foundations/messages/normalized-hash.mdx
+++ b/foundations/messages/normalized-hash.mdx
@@ -65,7 +65,6 @@ Many tools and libraries in the TON ecosystem support the normalized message has
| **ton/ton** (`@ton/ton`) | Yes | Use `storeMessage(..., { forceRef: true })` and custom logic to clear fields. See [Message lookup](/ecosystem/ton-connect/message-lookup) for an example. |
| **TonCenter** | Yes | API methods such as `sendBocReturnHash` return the normalized hash; transaction lookups support it. |
| **TonAPI** | Yes | [Transaction tracking](https://docs.tonconsole.com/tonapi/cookbook/transaction-tracking) and API lookups natively use the normalized hash. |
-| **Tongo** | Yes | The first implementation of the standard ([tonkeeper/tongo#313](https://github.com/tonkeeper/tongo/pull/313)). |
| **ton-blockchain/ton** | Yes | Supported at the node level ([ton-blockchain/ton#1557](https://github.com/ton-blockchain/ton/pull/1557)). |
From deb2ec4158356dcbfc84c0be33a28f3982740505 Mon Sep 17 00:00:00 2001
From: Novus Nota <68142933+novusnota@users.noreply.github.com>
Date: Mon, 23 Mar 2026 11:01:27 +0100
Subject: [PATCH 03/10] ai suggestion
---
foundations/messages/normalized-hash.mdx | 25 ++++++++++++------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/foundations/messages/normalized-hash.mdx b/foundations/messages/normalized-hash.mdx
index 0aec046a8..9d324772a 100644
--- a/foundations/messages/normalized-hash.mdx
+++ b/foundations/messages/normalized-hash.mdx
@@ -5,7 +5,7 @@ sidebarTitle: "Normalized hash"
import { Aside } from "/snippets/aside.jsx";
-The normalized message hash is a consistent and reliable identifier for [external-in](/foundations/messages/external-in) messages. It remains constant regardless of variations in the `src`, `import_fee`, and `init` fields, which can change without affecting the validity of the message. This hash is particularly useful for tracking transactions.
+The normalized message hash is a consistent identifier for [external-in](/foundations/messages/external-in) messages. It remains constant regardless of variations in the `src`, `import_fee`, and `init` fields, which can change without affecting the validity of the message. This hash is particularly useful for tracking transactions.
For the canonical specification, refer to [TEP-467: Normalized Message Hash](https://github.com/ton-blockchain/TEPs/blob/master/text/0467-normalized-message-hash.md).
@@ -13,9 +13,9 @@ The normalized message hash is a consistent and reliable identifier for [externa
## Why normalization is needed
-In TON, an external-in message can be constructed and packed in different ways that are all logically identical. Fields such as the source address (`src`), the `import_fee`, and the state initialization (`init`) can vary depending on the sender's implementation or the API provider processing the message.
+In TON, an external-in message can be constructed and packed in different ways that are all logically identical. Fields such as the source address (`src`), the `import_fee`, and the state initialization (`init`) can vary depending on the sender's implementation or the API provider processing the message.
-Because these non-essential fields are included when computing the standard cell hash, functionally identical messages can produce different message hashes. This variability complicates reliable transaction tracking and deduplication, as highlighted in the [TON Console transaction tracking guide](https://docs.tonconsole.com/academy/transaction-tracking).
+Because these non-essential fields are included when computing the standard cell hash, functionally identical messages can produce different message hashes. This variability complicates transaction tracking and deduplication, as highlighted in the [TON Console transaction tracking guide](https://docs.tonconsole.com/academy/transaction-tracking).
By applying normalization rules before calculating the hash, the variable fields are removed or zeroed out, ensuring that the same logical message always produces the exact same hash.
@@ -26,9 +26,9 @@ The normalized hash is computed by standardizing the `ext_in_msg_info$10` fields
According to TEP-467, apply the following rules:
1. **Source Address (`src`)**: Set to `addr_none$00`.
-2. **Import Fee (`import_fee`)**: Set to `0`.
-3. **InitState (`init`)**: Set to `nothing$0`.
-4. **Body (`body:(Either X ^X)`)**: Always store as a reference (`^X`). The content of the body itself is included without modification.
+1. **Import Fee (`import_fee`)**: Set to `0`.
+1. **InitState (`init`)**: Set to `nothing$0`.
+1. **Body (`body:(Either X ^X)`)**: Always store as a reference (`^X`). The content of the body itself is included without modification.
After constructing the cell with these standardized values, calculate its standard [cell hash](/foundations/serialization/cells) (the SHA-256 of the root cell).
@@ -60,12 +60,12 @@ const normalizedHash = normalizedExtMessage.hash().toString("hex");
Many tools and libraries in the TON ecosystem support the normalized message hash either natively or through API integration.
-| Tool | Support | Details |
-|------|---------|---------|
-| **ton/ton** (`@ton/ton`) | Yes | Use `storeMessage(..., { forceRef: true })` and custom logic to clear fields. See [Message lookup](/ecosystem/ton-connect/message-lookup) for an example. |
-| **TonCenter** | Yes | API methods such as `sendBocReturnHash` return the normalized hash; transaction lookups support it. |
-| **TonAPI** | Yes | [Transaction tracking](https://docs.tonconsole.com/tonapi/cookbook/transaction-tracking) and API lookups natively use the normalized hash. |
-| **ton-blockchain/ton** | Yes | Supported at the node level ([ton-blockchain/ton#1557](https://github.com/ton-blockchain/ton/pull/1557)). |
+| Tool | Support | Details |
+| ------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **ton/ton** (`@ton/ton`) | Yes | Use `storeMessage(..., { forceRef: true })` and custom logic to clear fields. See [Message lookup](/ecosystem/ton-connect/message-lookup) for an example. |
+| **TonCenter** | Yes | API methods such as `sendBocReturnHash` return the normalized hash; transaction lookups support it. |
+| **TonAPI** | Yes | [Transaction tracking](https://docs.tonconsole.com/tonapi/cookbook/transaction-tracking) and API lookups natively use the normalized hash. |
+| **ton-blockchain/ton** | Yes | Supported at the node level ([ton-blockchain/ton#1557](https://github.com/ton-blockchain/ton/pull/1557)). |
For a practical guide on searching for transactions using TON Connect and the normalized hash, see the [Message lookup](/ecosystem/ton-connect/message-lookup) guide.
@@ -84,4 +84,3 @@ However, the normalized message hash serves as a unique identifier for a specifi
For dApps interacting with user wallets via TON Connect, or for exchanges controlling their outbound external messages, it is safe to reference traces using the normalized hash. This applies even before the transactions are finalized.
-
From 4e907a591f6db609c405095d3f5abed597c85e45 Mon Sep 17 00:00:00 2001
From: Antonoff <35700168+memearchivarius@users.noreply.github.com>
Date: Mon, 23 Mar 2026 20:14:43 +0300
Subject: [PATCH 04/10] rework
-Removed part of theory from message lookup
-Revised wording for other cases
-Removed misleading info
---
ecosystem/ton-connect/message-lookup.mdx | 17 +++--------------
foundations/messages/external-in.mdx | 2 +-
foundations/messages/normalized-hash.mdx | 24 ++++++++++++++----------
3 files changed, 18 insertions(+), 25 deletions(-)
diff --git a/ecosystem/ton-connect/message-lookup.mdx b/ecosystem/ton-connect/message-lookup.mdx
index 2a6a22ffb..e1150ab39 100644
--- a/ecosystem/ton-connect/message-lookup.mdx
+++ b/ecosystem/ton-connect/message-lookup.mdx
@@ -16,18 +16,7 @@ The process of seeking a transaction associated with an `external-in` message is
### Message normalization
-Normalization is a standardization process that converts different external-in message representations into a consistent format. This needs to be done because the structure of external-in messages allows the same message to be constructed in different forms, which results in different possible hashes for the same external message.
-
-To address this, the ecosystem defines a standard that ensures consistent hash calculation. The normalization rules are specified in detail in the [TEP-467 proposal](https://github.com/ton-blockchain/TEPs/pull/467). Message lookup by its normalized hash is already implemented in most TON [RPC providers](/ecosystem/api/overview).
-
-**How normalization works:**
-
-The normalized hash is computed by applying the following standardization rules to an external-in message:
-
-1. **Source Address (`src`)**: set to `addr_none$00`
-1. **Import Fee (`import_fee`)**: set to `0`
-1. **InitState (`init`)**: set to an empty value
-1. **Body**: always stored as a reference
+Message lookup uses normalized hash because different serializers can produce different raw hashes for external-in messages. To avoid mismatches, clients and providers calculate a canonical lookup key defined by [TEP-467](https://github.com/ton-blockchain/TEPs/blob/master/text/0467-normalized-message-hash.md). Most TON [RPC providers](/ecosystem/api/overview) support lookup by this key.
For more details on the standardization process, language-agnostic implementations, and uniqueness constraints, see the [Normalized message hash](/foundations/messages/normalized-hash) documentation.
@@ -39,7 +28,7 @@ The normalized hash is computed by applying the following standardization rules
/**
* Generates a normalized hash of an "external-in" message for comparison.
*
- * This function ensures consistent hashing of external-in messages by following [TEP-467](https://github.com/ton-blockchain/TEPs/blob/8b3beda2d8611c90ec02a18bec946f5e33a80091/text/0467-normalized-message-hash.md):
+ * This function ensures consistent hashing of external-in messages by following [TEP-467](https://github.com/ton-blockchain/TEPs/blob/master/text/0467-normalized-message-hash.md):
*
* @param {Message} message - The message to be normalized and hashed. Must be of type `"external-in"`.
* @returns {Buffer} The hash of the normalized message.
@@ -268,6 +257,6 @@ if (tx) {
## See also
-- [TEP-467: Normalized Message Hash](https://github.com/ton-blockchain/TEPs/blob/8b3beda2d8611c90ec02a18bec946f5e33a80091/text/0467-normalized-message-hash.md)
+- [TEP-467: Normalized Message Hash](https://github.com/ton-blockchain/TEPs/blob/master/text/0467-normalized-message-hash.md)
- [Messages and transactions](/foundations/messages/ordinary-tx)
- [TON Connect: Sending messages](/ecosystem/ton-connect/overview)
diff --git a/foundations/messages/external-in.mdx b/foundations/messages/external-in.mdx
index f3a3149a2..1656033a6 100644
--- a/foundations/messages/external-in.mdx
+++ b/foundations/messages/external-in.mdx
@@ -43,4 +43,4 @@ Incoming external messages are sent to the contract from outside the blockchain,
When an incoming external message is sent to the blockchain, validators share them with each other, and might accidentally (or intentionally) deliver it several times. As it's usually preferred to process a unique incoming external message only once, some measures need to be taken to ensure duplicate messages are not accepted. Some of these techniques can be found in [wallet](/standard/wallets/comparison) contracts.
-For reliable off-chain transaction tracking, the ecosystem relies on the [normalized message hash](/foundations/messages/normalized-hash) standard.
+For off-chain transaction tracking, the ecosystem relies on the [normalized message hash](/foundations/messages/normalized-hash) standard.
diff --git a/foundations/messages/normalized-hash.mdx b/foundations/messages/normalized-hash.mdx
index 9d324772a..61d47b384 100644
--- a/foundations/messages/normalized-hash.mdx
+++ b/foundations/messages/normalized-hash.mdx
@@ -5,7 +5,7 @@ sidebarTitle: "Normalized hash"
import { Aside } from "/snippets/aside.jsx";
-The normalized message hash is a consistent identifier for [external-in](/foundations/messages/external-in) messages. It remains constant regardless of variations in the `src`, `import_fee`, and `init` fields, which can change without affecting the validity of the message. This hash is particularly useful for tracking transactions.
+The normalized message hash is a canonical identifier used to look up [external-in](/foundations/messages/external-in) messages across APIs and SDKs. It is computed from a standardized external-in representation so different serializers produce the same lookup key.
For the canonical specification, refer to [TEP-467: Normalized Message Hash](https://github.com/ton-blockchain/TEPs/blob/master/text/0467-normalized-message-hash.md).
@@ -13,11 +13,11 @@ The normalized message hash is a consistent identifier for [external-in](/founda
## Why normalization is needed
-In TON, an external-in message can be constructed and packed in different ways that are all logically identical. Fields such as the source address (`src`), the `import_fee`, and the state initialization (`init`) can vary depending on the sender's implementation or the API provider processing the message.
+In TON, clients and providers can serialize external-in messages with structural differences that lead to different raw hashes for the same lookup intent. This affects fields and layout choices used in hashing, such as `src`, `import_fee`, `init`, and whether the body is embedded or referenced.
-Because these non-essential fields are included when computing the standard cell hash, functionally identical messages can produce different message hashes. This variability complicates transaction tracking and deduplication, as highlighted in the [TON Console transaction tracking guide](https://docs.tonconsole.com/academy/transaction-tracking).
+Providers usually do not rewrite message content. The mismatch appears because systems may hash slightly different structural representations. For example, `init` is meaningful in message semantics, but normalization sets it to `nothing$0` when building a canonical lookup form.
-By applying normalization rules before calculating the hash, the variable fields are removed or zeroed out, ensuring that the same logical message always produces the exact same hash.
+Apply normalization rules only to compute a lookup key. This process builds a canonical external-in representation for hashing and does not mutate an already sent message.
## Calculate the normalized hash
@@ -30,16 +30,16 @@ According to TEP-467, apply the following rules:
1. **InitState (`init`)**: Set to `nothing$0`.
1. **Body (`body:(Either X ^X)`)**: Always store as a reference (`^X`). The content of the body itself is included without modification.
-After constructing the cell with these standardized values, calculate its standard [cell hash](/foundations/serialization/cells) (the SHA-256 of the root cell).
+After constructing the canonical external-in message cell, compute its standard [cell hash](/foundations/serialization/cells).
### Low-level construction example
-The following TypeScript example demonstrates the raw cell construction. This logic illustrates the underlying TL-B serialization and can be adapted to any programming language or SDK.
+The following TypeScript example builds the canonical external-in cell used for normalized hash calculation. This logic illustrates the underlying TL-B serialization and can be adapted to any programming language or SDK.
```typescript
import { beginCell, Cell, Address } from "@ton/core";
-function normalizeExternalMessage(destAddress: Address, bodyCell: Cell): Cell {
+function buildNormalizedExtInMessage(destAddress: Address, bodyCell: Cell): Cell {
return beginCell()
.storeUint(0b10, 2) // external-in message prefix
.storeUint(0b00, 2) // src: addr_none$00
@@ -52,7 +52,7 @@ function normalizeExternalMessage(destAddress: Address, bodyCell: Cell): Cell {
}
// Compute the standard cell hash
-const normalizedExtMessage = normalizeExternalMessage(destAddress, bodyCell);
+const normalizedExtMessage = buildNormalizedExtInMessage(destAddress, bodyCell);
const normalizedHash = normalizedExtMessage.hash().toString("hex");
```
@@ -81,6 +81,10 @@ However, the normalized message hash serves as a unique identifier for a specifi
- The message includes an instruction to send an internal message with the `IGNORE_ERRORS=+2` flag (this is standard behavior for [TON Connect](/ecosystem/ton-connect/overview) and for wallets starting from v5).
- The wallet contract is never deleted.
-
- For dApps interacting with user wallets via TON Connect, or for exchanges controlling their outbound external messages, it is safe to reference traces using the normalized hash. This applies even before the transactions are finalized.
+### What to use for global uniqueness
+
+Use normalized hash as a lookup correlation key before confirmation. After a transaction is found, use the transaction identifier for global uniqueness, such as account address + transaction LT (or transaction hash, when available in your integration).
+
+
+ Read more about external message tracking from the TONAPI side in [TONAPI docs](https://docs.tonconsole.com/academy/transaction-tracking).
From 5b9539f802f1382344b5cb347c44dd9b1d6dcf7e Mon Sep 17 00:00:00 2001
From: Antonoff <35700168+memearchivarius@users.noreply.github.com>
Date: Mon, 23 Mar 2026 20:19:47 +0300
Subject: [PATCH 05/10] TonAPI
---
foundations/messages/normalized-hash.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/foundations/messages/normalized-hash.mdx b/foundations/messages/normalized-hash.mdx
index 61d47b384..ca2cf53a0 100644
--- a/foundations/messages/normalized-hash.mdx
+++ b/foundations/messages/normalized-hash.mdx
@@ -86,5 +86,5 @@ However, the normalized message hash serves as a unique identifier for a specifi
Use normalized hash as a lookup correlation key before confirmation. After a transaction is found, use the transaction identifier for global uniqueness, such as account address + transaction LT (or transaction hash, when available in your integration).
- Read more about external message tracking from the TONAPI side in [TONAPI docs](https://docs.tonconsole.com/academy/transaction-tracking).
+ Read more about external message tracking from the TonAPI side in [TonAPI docs](https://docs.tonconsole.com/academy/transaction-tracking).
From c2fa65370e4b397c1408d79516758bd748a608dd Mon Sep 17 00:00:00 2001
From: Antonoff <35700168+memearchivarius@users.noreply.github.com>
Date: Tue, 24 Mar 2026 17:22:05 +0300
Subject: [PATCH 06/10] Update normalized-hash.mdx
---
foundations/messages/normalized-hash.mdx | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/foundations/messages/normalized-hash.mdx b/foundations/messages/normalized-hash.mdx
index ca2cf53a0..164a20e11 100644
--- a/foundations/messages/normalized-hash.mdx
+++ b/foundations/messages/normalized-hash.mdx
@@ -60,12 +60,12 @@ const normalizedHash = normalizedExtMessage.hash().toString("hex");
Many tools and libraries in the TON ecosystem support the normalized message hash either natively or through API integration.
-| Tool | Support | Details |
-| ------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| **ton/ton** (`@ton/ton`) | Yes | Use `storeMessage(..., { forceRef: true })` and custom logic to clear fields. See [Message lookup](/ecosystem/ton-connect/message-lookup) for an example. |
-| **TonCenter** | Yes | API methods such as `sendBocReturnHash` return the normalized hash; transaction lookups support it. |
-| **TonAPI** | Yes | [Transaction tracking](https://docs.tonconsole.com/tonapi/cookbook/transaction-tracking) and API lookups natively use the normalized hash. |
-| **ton-blockchain/ton** | Yes | Supported at the node level ([ton-blockchain/ton#1557](https://github.com/ton-blockchain/ton/pull/1557)). |
+| Tool | Details |
+| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **ton/ton** (`@ton/ton`) | Use `storeMessage(..., { forceRef: true })` and custom logic to clear fields. See [Message lookup](/ecosystem/ton-connect/message-lookup) for an example. |
+| **TonCenter** | API methods such as `sendBocReturnHash` return the normalized hash; transaction lookups support it. |
+| **TonAPI** | [Transaction tracking](https://docs.tonconsole.com/tonapi/cookbook/transaction-tracking) and API lookups natively use the normalized hash. |
+| **ton-blockchain/ton** | Supported in the [tonlib](https://github.com/ton-blockchain/ton/pull/1557) to enable `sendBocReturnHash`. |
For a practical guide on searching for transactions using TON Connect and the normalized hash, see the [Message lookup](/ecosystem/ton-connect/message-lookup) guide.
From a9870ea11feae590a62bea10d40fb3c6608e3d7d Mon Sep 17 00:00:00 2001
From: Antonoff <35700168+memearchivarius@users.noreply.github.com>
Date: Tue, 24 Mar 2026 17:27:49 +0300
Subject: [PATCH 07/10] Update message-lookup.mdx
Small fixes
---
ecosystem/ton-connect/message-lookup.mdx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ecosystem/ton-connect/message-lookup.mdx b/ecosystem/ton-connect/message-lookup.mdx
index e1150ab39..8613b0676 100644
--- a/ecosystem/ton-connect/message-lookup.mdx
+++ b/ecosystem/ton-connect/message-lookup.mdx
@@ -7,7 +7,7 @@ import { Aside } from "/snippets/aside.jsx";
- You should never use external message tracking for payment processing purposes. Check out [payment processing](/payments/overview) for more details.
+ Do not use external message tracking for payment processing. Check out [payment processing](/payments/overview) for more details.
## Introduction
@@ -164,7 +164,7 @@ if (tx) {
}
```
-## Waiting for transaction confirmation
+## Wait for transaction confirmation
If you’ve just sent a message, it may take a few seconds before it appears on-chain.
The function `waitForTransaction` to poll the blockchain and wait for the corresponding transaction should be used in this case:
From a37fd482d288e1e2bcb0761e313fc8608120a218 Mon Sep 17 00:00:00 2001
From: Antonoff <35700168+memearchivarius@users.noreply.github.com>
Date: Wed, 25 Mar 2026 11:51:40 +0300
Subject: [PATCH 08/10] Apply suggestion from @github-actions[bot]
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
---
foundations/messages/normalized-hash.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/foundations/messages/normalized-hash.mdx b/foundations/messages/normalized-hash.mdx
index 164a20e11..97666fe04 100644
--- a/foundations/messages/normalized-hash.mdx
+++ b/foundations/messages/normalized-hash.mdx
@@ -8,7 +8,7 @@ import { Aside } from "/snippets/aside.jsx";
The normalized message hash is a canonical identifier used to look up [external-in](/foundations/messages/external-in) messages across APIs and SDKs. It is computed from a standardized external-in representation so different serializers produce the same lookup key.
- For the canonical specification, refer to [TEP-467: Normalized Message Hash](https://github.com/ton-blockchain/TEPs/blob/master/text/0467-normalized-message-hash.md).
+ This page documents the canonical normalized message hash used across TON tooling. The underlying proposal is formalized in [TEP-467: Normalized Message Hash](https://github.com/ton-blockchain/TEPs/blob/master/text/0467-normalized-message-hash.md).
## Why normalization is needed
From 5ebb1ffeb3df5910a87822237301959346b0bc7c Mon Sep 17 00:00:00 2001
From: Antonoff <35700168+memearchivarius@users.noreply.github.com>
Date: Wed, 25 Mar 2026 12:13:29 +0300
Subject: [PATCH 09/10] Revised support section
---
foundations/messages/normalized-hash.mdx | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/foundations/messages/normalized-hash.mdx b/foundations/messages/normalized-hash.mdx
index 97666fe04..b044934c3 100644
--- a/foundations/messages/normalized-hash.mdx
+++ b/foundations/messages/normalized-hash.mdx
@@ -60,15 +60,15 @@ const normalizedHash = normalizedExtMessage.hash().toString("hex");
Many tools and libraries in the TON ecosystem support the normalized message hash either natively or through API integration.
-| Tool | Details |
-| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| **ton/ton** (`@ton/ton`) | Use `storeMessage(..., { forceRef: true })` and custom logic to clear fields. See [Message lookup](/ecosystem/ton-connect/message-lookup) for an example. |
-| **TonCenter** | API methods such as `sendBocReturnHash` return the normalized hash; transaction lookups support it. |
-| **TonAPI** | [Transaction tracking](https://docs.tonconsole.com/tonapi/cookbook/transaction-tracking) and API lookups natively use the normalized hash. |
-| **ton-blockchain/ton** | Supported in the [tonlib](https://github.com/ton-blockchain/ton/pull/1557) to enable `sendBocReturnHash`. |
+| Tool | Details |
+| ---------------------- | --------------------------------------------------------------------------------------------------------- |
+| **@ton/ton** | Example of usage in [message lookup](/ecosystem/ton-connect/message-lookup). |
+| **TonCenter** | API methods such as `/api/v2/sendBocReturnHash` or `/api/v3/traces` natively use the normalized hash. |
+| **TonAPI** | API lookups like `getBlockchainTransactionByMessageHashGet` natively use the normalized hash. |
+| **ton-blockchain/ton** | Supported in the [tonlib](https://github.com/ton-blockchain/ton/pull/1557) to enable `sendBocReturnHash`. |
- For a practical guide on searching for transactions using TON Connect and the normalized hash, see the [Message lookup](/ecosystem/ton-connect/message-lookup) guide.
+ A normalized hash can be resolved only by [full blockchain indexers](/ecosystem/api/overview). Lite servers and archive nodes do not understand it.
## Uniqueness constraints
From 7f9c2332dd106719263962d0d162652945d8c0f3 Mon Sep 17 00:00:00 2001
From: Antonoff <35700168+memearchivarius@users.noreply.github.com>
Date: Wed, 25 Mar 2026 12:15:33 +0300
Subject: [PATCH 10/10] lower case link
---
ecosystem/ton-connect/message-lookup.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ecosystem/ton-connect/message-lookup.mdx b/ecosystem/ton-connect/message-lookup.mdx
index 8613b0676..a6c99b194 100644
--- a/ecosystem/ton-connect/message-lookup.mdx
+++ b/ecosystem/ton-connect/message-lookup.mdx
@@ -19,7 +19,7 @@ The process of seeking a transaction associated with an `external-in` message is
Message lookup uses normalized hash because different serializers can produce different raw hashes for external-in messages. To avoid mismatches, clients and providers calculate a canonical lookup key defined by [TEP-467](https://github.com/ton-blockchain/TEPs/blob/master/text/0467-normalized-message-hash.md). Most TON [RPC providers](/ecosystem/api/overview) support lookup by this key.
- For more details on the standardization process, language-agnostic implementations, and uniqueness constraints, see the [Normalized message hash](/foundations/messages/normalized-hash) documentation.
+ For more details on the standardization process, language-agnostic implementations, and uniqueness constraints, see the [normalized message hash](/foundations/messages/normalized-hash) documentation.
## Transaction lookup using external message from TON Connect