> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ton.org/llms.txt
> Use this file to discover all available pages before exploring further.

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.ton.org/feedback

```json
{
  "path": "/standard/wallets/highload/v3/verify-is-processed",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# How to verify message is processed

export const Aside = ({type = "note", title = "", icon = "", iconType = "regular", children}) => {
  const asideVariants = ["note", "tip", "caution", "danger"];
  const asideComponents = {
    note: {
      outerStyle: "border-sky-500/20 bg-sky-50/50 dark:border-sky-500/30 dark:bg-sky-500/10",
      innerStyle: "text-sky-900 dark:text-sky-200",
      calloutType: "note",
      icon: <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-sky-500" aria-label="Note">
          <path fill-rule="evenodd" clip-rule="evenodd" d="M7 1.3C10.14 1.3 12.7 3.86 12.7 7C12.7 10.14 10.14 12.7 7 12.7C5.48908 12.6974 4.0408 12.096 2.97241 11.0276C1.90403 9.9592 1.30264 8.51092 1.3 7C1.3 3.86 3.86 1.3 7 1.3ZM7 0C3.14 0 0 3.14 0 7C0 10.86 3.14 14 7 14C10.86 14 14 10.86 14 7C14 3.14 10.86 0 7 0ZM8 3H6V8H8V3ZM8 9H6V11H8V9Z"></path>
        </svg>
    },
    tip: {
      outerStyle: "border-emerald-500/20 bg-emerald-50/50 dark:border-emerald-500/30 dark:bg-emerald-500/10",
      innerStyle: "text-emerald-900 dark:text-emerald-200",
      calloutType: "tip",
      icon: <svg width="11" height="14" viewBox="0 0 11 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="text-emerald-600 dark:text-emerald-400/80 w-3.5 h-auto" aria-label="Tip">
          <path d="M3.12794 12.4232C3.12794 12.5954 3.1776 12.7634 3.27244 12.907L3.74114 13.6095C3.88471 13.8248 4.21067 14 4.46964 14H6.15606C6.41415 14 6.74017 13.825 6.88373 13.6095L7.3508 12.9073C7.43114 12.7859 7.49705 12.569 7.49705 12.4232L7.50055 11.3513H3.12521L3.12794 12.4232ZM5.31288 0C2.52414 0.00875889 0.5 2.26889 0.5 4.78826C0.5 6.00188 0.949566 7.10829 1.69119 7.95492C2.14321 8.47011 2.84901 9.54727 3.11919 10.4557C3.12005 10.4625 3.12175 10.4698 3.12261 10.4771H7.50342C7.50427 10.4698 7.50598 10.463 7.50684 10.4557C7.77688 9.54727 8.48281 8.47011 8.93484 7.95492C9.67728 7.13181 10.1258 6.02703 10.1258 4.78826C10.1258 2.15486 7.9709 0.000106649 5.31288 0ZM7.94902 7.11267C7.52078 7.60079 6.99082 8.37878 6.6077 9.18794H4.02051C3.63739 8.37878 3.10743 7.60079 2.67947 7.11294C2.11997 6.47551 1.8126 5.63599 1.8126 4.78826C1.8126 3.09829 3.12794 1.31944 5.28827 1.3126C7.2435 1.3126 8.81315 2.88226 8.81315 4.78826C8.81315 5.63599 8.50688 6.47551 7.94902 7.11267ZM4.87534 2.18767C3.66939 2.18767 2.68767 3.16939 2.68767 4.37534C2.68767 4.61719 2.88336 4.81288 3.12521 4.81288C3.36705 4.81288 3.56274 4.61599 3.56274 4.37534C3.56274 3.6515 4.1515 3.06274 4.87534 3.06274C5.11719 3.06274 5.31288 2.86727 5.31288 2.62548C5.31288 2.38369 5.11599 2.18767 4.87534 2.18767Z"></path>
        </svg>
    },
    caution: {
      outerStyle: "border-amber-500/20 bg-amber-50/50 dark:border-amber-500/30 dark:bg-amber-500/10",
      innerStyle: "text-amber-900 dark:text-amber-200",
      calloutType: "warning",
      icon: <svg className="flex-none w-5 h-5 text-amber-400 dark:text-amber-300/80" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-label="Warning">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
        </svg>
    },
    danger: {
      outerStyle: "border-red-500/20 bg-red-50/50 dark:border-red-500/30 dark:bg-red-500/10",
      innerStyle: "text-red-900 dark:text-red-200",
      calloutType: "danger",
      icon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" className="text-red-600 dark:text-red-400/80 w-4 h-4" aria-label="Danger">
          <path d="M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zm41.6-48c-4.3 7.4-4.3 16.6 0 24l88.3 152.9c4.3 7.4 12.2 12 20.8 12l176.6 0c8.6 0 16.5-4.6 20.8-12L453.4 268c4.3-7.4 4.3-16.6 0-24L365.1 91.1c-4.3-7.4-12.2-12-20.8-12l-176.6 0c-8.6 0-16.5 4.6-20.8 12L58.6 244zM256 128c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"></path>
        </svg>
    }
  };
  let variant = type;
  let gotInvalidVariant = false;
  if (!asideVariants.includes(type)) {
    gotInvalidVariant = true;
    variant = "danger";
  }
  const iconVariants = ["regular", "solid", "light", "thin", "sharp-solid", "duotone", "brands"];
  if (!iconVariants.includes(iconType)) {
    iconType = "regular";
  }
  return <>
      <div className={`callout my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border ${asideComponents[variant].outerStyle}`} data-callout-type={asideComponents[variant].calloutType}>
        <div className="mt-0.5 w-4" data-component-part="callout-icon">
          {}
          {icon === "" ? asideComponents[variant].icon : <Icon icon={icon} iconType={iconType} size={14} />}
        </div>
        <div className={`text-sm prose min-w-0 w-full ${asideComponents[variant].innerStyle}`} data-component-part="callout-content">
          {gotInvalidVariant ? <p>
              <span className="font-bold">
                Invalid <code>type</code> passed!
              </span>
              <br />
              <span className="font-bold">Received: </span>
              {type}
              <br />
              <span className="font-bold">Expected one of: </span>
              {asideVariants.join(", ")}
            </p> : <>
              {title && <p className="font-bold">{title}</p>}
              {children}
            </>}
        </div>
      </div>
    </>;
};

This guide shows how to verify that a transfer (single or batch) was fully processed across both transactions.

## Objective

By the end of this guide, you will:

* Verify that both transactions (external and internal) succeeded
* Calculate how many messages were successfully sent
* Detect partial failures in batch transfers

## Prerequisites

* Completed [wallet creation](/standard/wallets/highload/v3/create) with funded balance
* Sent at least one transfer (single or batch)
* Know the `query_id` and `created_at` values used in the transfer

## Verification overview

Highload Wallet v3 uses a two-transaction pattern. To verify full processing, you need to check both transactions:

1. **External transaction (Transaction 1):** Validates the message and marks `query_id` as processed
2. **Internal transaction (Transaction 2):** Processes the action list and sends outgoing messages

Even if `processed?` returns `true`, the internal transaction may have failed. Full verification requires checking both transactions.

See [Message sending flow](/standard/wallets/highload/v3/specification#message-sending-flow) for the complete two-transaction pattern.

## Helper functions

Create helper functions for transaction search and parsing:

```typescript theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
import { TonClient } from '@ton/ton';
import { Cell, Transaction, Address } from '@ton/core';

// Retry helper for network requests
async function retry<T>(fn: () => Promise<T>, options: { retries: number; delay: number }): Promise<T> {
    let lastError: Error | undefined;
    for (let i = 0; i < options.retries; i++) {
        try {
            return await fn();
        } catch (e) {
            if (e instanceof Error) lastError = e;
            await new Promise((resolve) => setTimeout(resolve, options.delay));
        }
    }
    throw lastError;
}

// Parse external message to extract query_id and created_at
function parseExternalMessageBody(body: Cell) {
    try {
        const inner = body.refs[0]!.beginParse();
        inner.skip(32 + 8); // Skip subwalletId and mode
        const queryId = inner.loadUintBig(23);
        const createdAt = inner.loadUint(64);
        
        return { queryId, createdAt };
    } catch (e) {
        return null;
    }
}

// Generic transaction finder with pagination
async function findTransaction(
    client: TonClient,
    address: Address,
    predicate: (tx: Transaction) => boolean
): Promise<Transaction | null> {
    let lt: string | undefined = undefined;
    let hash: string | undefined = undefined;
    
    while (true) {
        const transactions = await retry(
            () => client.getTransactions(address, {
                hash,
                lt,
                limit: 20,
                archival: true,
            }),
            { delay: 1000, retries: 3 }
        );
        
        if (transactions.length === 0) return null;
        
        const found = transactions.find(predicate);
        if (found) return found;
        
        const last = transactions.at(-1)!;
        lt = last.lt.toString();
        hash = last.hash().toString('base64');
    }
}
```

## Step 1: Set up and check if processed

Load wallet configuration and check if the `query_id` was marked as processed:

```typescript theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
import { mnemonicToPrivateKey } from '@ton/crypto';
import { HighloadWalletV3 } from './wrappers/HighloadWalletV3';
import { HighloadQueryId } from './wrappers/HighloadQueryId';
import * as fs from 'fs';

// Load wallet data
const walletData = JSON.parse(fs.readFileSync('.wallet.json', 'utf-8'));
const keyPair = await mnemonicToPrivateKey(walletData.mnemonic.split(' '));

const CODE = Cell.fromBoc(Buffer.from('b5ee9c7241021001000228000114ff00f4a413f4bcf2c80b01020120020d02014803040078d020d74bc00101c060b0915be101d0d3030171b0915be0fa4030f828c705b39130e0d31f018210ae42e5a4ba9d8040d721d74cf82a01ed55fb04e030020120050a02027306070011adce76a2686b85ffc00201200809001aabb6ed44d0810122d721d70b3f0018aa3bed44d08307d721d70b1f0201200b0c001bb9a6eed44d0810162d721d70b15800e5b8bf2eda2edfb21ab09028409b0ed44d0810120d721f404f404d33fd315d1058e1bf82325a15210b99f326df82305aa0015a112b992306dde923033e2923033e25230800df40f6fa19ed021d721d70a00955f037fdb31e09130e259800df40f6fa19cd001d721d70a00937fdb31e0915be270801f6f2d48308d718d121f900ed44d0d3ffd31ff404f404d33fd315d1f82321a15220b98e12336df82324aa00a112b9926d32de58f82301de541675f910f2a106d0d31fd4d307d30cd309d33fd315d15168baf2a2515abaf2a6f8232aa15250bcf2a304f823bbf2a35304800df40f6fa199d024d721d70a00f2649130e20e01fe5309800df40f6fa18e13d05004d718d20001f264c858cf16cf8301cf168e1030c824cf40cf8384095005a1a514cf40e2f800c94039800df41704c8cbff13cb1ff40012f40012cb3f12cb15c9ed54f80f21d0d30001f265d3020171b0925f03e0fa4001d70b01c000f2a5fa4031fa0031f401fa0031fa00318060d721d300010f0020f265d2000193d431d19130e272b1fb00b585bf03', 'hex'))[0];

const client = new TonClient({ 
    endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC', // This is TESTNET endpoint
    // apiKey: 'your-api-key' // Optional: get from @tonapibot or @tontestnetapibot
});

const highloadWallet = HighloadWalletV3.createFromConfig(
    {
        publicKey: keyPair.publicKey,
        subwalletId: walletData.subwalletId,
        timeout: walletData.timeout,
    },
    CODE
);
const wallet = client.open(highloadWallet);

// The query_id and created_at from your transfer
const queryId = HighloadQueryId.fromSeqno(17n);
const createdAt = 1759878156; // Your actual created_at timestamp

// Check if processed
const isProcessed = await wallet.getProcessed(queryId);
if (!isProcessed) {
    console.log('❌ Query not processed');
    return;
}
console.log('✓ Query marked as processed');
```

<Aside type="note">
  **What `processed?` tells you:** This GET method only confirms that the `query_id` was marked as processed in the wallet's storage. It does **not** confirm that the internal transaction succeeded or that messages were sent.

  See [`processed?` method](/standard/wallets/highload/v3/specification#processed%3F-method-details) in the specification for details.
</Aside>

## Step 2: Find and verify external transaction

Search transaction history to find the external transaction by `query_id` and `created_at`:

```typescript theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
// Find external transaction by query_id + created_at
async function findHighloadExternalTransaction(
    client: TonClient,
    walletAddress: Address,
    queryId: HighloadQueryId,
    createdAt: number
): Promise<Transaction | null> {
    const targetQueryId = queryId.getQueryId();
    
    return findTransaction(client, walletAddress, (tx) => {
        if (tx.inMessage?.info.type !== 'external-in') return false;
        if (!tx.inMessage.body) return false;
        
        const parsed = parseExternalMessageBody(tx.inMessage.body);
        if (!parsed) return false;
        
        return parsed.queryId === targetQueryId && parsed.createdAt === createdAt;
    });
}

const externalTx = await findHighloadExternalTransaction(
    client,
    highloadWallet.address,
    queryId,
    createdAt
);

if (!externalTx) {
    console.log('❌ External transaction not found');
    return;
}

// Verify external transaction compute phase
if (externalTx.description.type !== 'generic') {
    console.log('❌ Invalid transaction');
    return;
}

const externalCompute = externalTx.description.computePhase;
if (!externalCompute.success || externalCompute.exitCode !== 0) {
    console.log(`❌ External transaction failed: exit code ${externalCompute.exitCode}`);
    return;
}

console.log('✓ External transaction succeeded');
```

If the external transaction failed, see [Exit codes](/standard/wallets/highload/v3/specification#exit-codes) for troubleshooting.

## Step 3: Find and verify internal transaction

Follow the transaction chain to find and verify Transaction 2:

```typescript theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
// Find internal transaction by prevTransactionLt
async function findHighloadInternalTransaction(
    client: TonClient,
    walletAddress: Address,
    externalLt: string
): Promise<Transaction | null> {
    return findTransaction(client, walletAddress, (tx) => 
        tx.prevTransactionLt.toString() === externalLt
    );
}

// Check for outgoing messages
if (externalTx.outMessagesCount === 0) {
    console.log('❌ No outgoing messages from external transaction');
    return;
}

// Find the internal transaction
const internalTx = await findHighloadInternalTransaction(
    client,
    highloadWallet.address,
    externalTx.lt.toString()
);

if (!internalTx || internalTx.description.type !== 'generic') {
    console.log('❌ Internal transaction not found');
    return;
}

// Verify compute phase
if (internalTx.description.computePhase.type !== 'vm') {
    console.log('❌ Compute phase skipped');
    return;
}

const internalCompute = internalTx.description.computePhase;
if (!internalCompute.success || internalCompute.exitCode !== 0) {
    console.log(`❌ Internal transaction failed: exit code ${internalCompute.exitCode}`);
    return;
}

// Verify action phase
if (!internalTx.description.actionPhase) {
    console.log('❌ No action phase in internal transaction');
    return;
}

const action = internalTx.description.actionPhase;
if (!action.success) {
    console.log(`❌ Action phase failed: result code ${action.resultCode}`);
    return;
}

console.log('✓ Internal transaction succeeded');
```

<Aside type="note">
  **Transaction linking:** The external transaction creates an outgoing message with `outMsg.createdLt`. The internal transaction that processes this message has `prevTransactionLt` equal to the external transaction's `lt`. This creates a verifiable chain between the two transactions.
</Aside>

## Step 4: Calculate sent messages

Calculate how many messages were successfully sent:

```typescript theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
// Calculate messages sent (total actions - 1 for set_code)
const messageActions = action.totalActions - 1;
const messagesSent = action.messagesCreated;
const messagesFailed = action.skippedActions;

if (messagesFailed > 0) {
    console.log(`✅ Sent ${messagesSent}/${messageActions} messages (${messagesFailed} failed)`);
} else {
    console.log(`✅ Sent ${messagesSent}/${messageActions} messages`);
}
```

<Aside type="caution">
  **Partial failures:** Even if the action phase succeeds overall, some individual messages may fail. Check `skippedActions` to detect partial failures. If `skippedActions > 0`, some messages in the batch were not sent.

  The `totalActions - 1` calculation accounts for the [`set_code` protection](/standard/wallets/highload/v3/specification#protection-against-set-code) action.
</Aside>

## Expected outputs

### Full success

```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
✓ Query marked as processed
✓ External transaction succeeded
✓ Internal transaction succeeded
✅ Sent 10/10 messages
```

### Partial success

```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
✓ Query marked as processed
✓ External transaction succeeded
✓ Internal transaction succeeded
✅ Sent 8/10 messages (2 failed)
```

### External transaction failure

```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
✓ Query marked as processed
❌ External transaction failed: exit code 35
```

The `query_id` is marked as processed, but the transaction failed during validation. See [Exit codes](/standard/wallets/highload/v3/specification#exit-codes) for troubleshooting.

### Internal transaction failure

```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
✓ Query marked as processed
✓ External transaction succeeded
❌ Internal transaction failed: exit code 9
```

Transaction 1 succeeded (replay protection applied), but Transaction 2 failed. The `query_id` cannot be reused.

### Action phase failure

```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
✓ Query marked as processed
✓ External transaction succeeded
❌ Action phase failed: result code 37
```

Both transactions were executed, but the action phase failed to send messages.

## Next steps

You can now verify any transfer to ensure it was fully processed. This is especially important for batch transfers where partial failures can occur.
