> ## 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": "/ecosystem/appkit/jettons",
  "feedback": "Description of the issue"
}
```

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

</AgentInstructions>

# How to work with Jettons using AppKit

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>
    </>;
};

<Aside>
  [Initialize the AppKit](/ecosystem/appkit/init) before using examples on this page.
</Aside>

[Jettons](/standard/tokens/jettons/overview) are fungible tokens on TON, similar to ERC-20 tokens on Ethereum. Unlike Toncoin, which is the native TON currency used in all transfers, each jetton has a separate master (minter) contract and an individual wallet contract for each holder.

For example, USDT on TON is implemented as a jetton, and its minter contract address is `EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs`. By providing this address and the recipient's TON wallet contract address, AppKit knows which tokens to send and to whom.

<Aside type="note">
  To deploy and mint a new jetton on the mainnet without writing code, use the dedicated official tool: [TON MINTER](https://minter.ton.org).
</Aside>

## Metadata

Retrieve metadata about a specific jetton, such as its name, symbol, and decimals:

<CodeGroup>
  ```tsx title="React" icon="react" 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 { useJettonInfo } from '@ton/appkit-react';

  export const JettonCard = ({ jettonAddress }) => {
    const {
      data: info,
      isLoading,
      error,
    } = useJettonInfo({
      // Jetton master (minter) contract address
      address: jettonAddress,
    });

    if (isLoading) {
      return <div>Loading...</div>;
    }

    if (error) {
      return <div>Error: {error.message}</div>;
    }

    return (
      <div>
        <p><em>Jetton info</em></p>
        <p>Name: {info?.name}</p>
        <p>Symbol: {info?.symbol}</p>
        <p>Decimals: {info?.decimals}</p>
      </div>
    );
  };
  ```

  ```ts title="TypeScript" icon="globe" 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 { type AppKit, getJettonInfo } from '@ton/appkit';

  async function fetchJettonInfo(
    /** Initialized AppKit instance */
    kit: AppKit,
    /** Jetton master (minter) contract address */
    jettonAddress: string,
  ) {
    const info = await getJettonInfo(kit, {
      address: jettonAddress,
    });
    console.log('Jetton info:', info);
  }
  ```
</CodeGroup>

### Jetton wallet address

Each jetton holder has a dedicated jetton wallet contract. To resolve its address for a given owner:

<CodeGroup>
  ```tsx title="React" icon="react" expandable 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 {
    useJettonWalletAddress,
    useAddress,
  } from '@ton/appkit-react';

  export const JettonWalletAddressCard = ({ jettonAddress }) => {
    const ownerAddress = useAddress();
    const {
      data: walletAddress,
      isLoading,
      error,
    } = useJettonWalletAddress({
      // TON wallet address of the jetton holder
      ownerAddress: ownerAddress ?? '<TON_WALLET_ADDRESS>',

      // Jetton master (minter) contract address
      jettonAddress,
    });

    if (isLoading) {
      return <div>Loading...</div>;
    }

    if (error) {
      return <div>Error: {error.message}</div>;
    }

    return <div>Jetton wallet address: {walletAddress?.toString()}</div>;
  };
  ```

  ```ts title="TypeScript" icon="globe" expandable 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 {
    type AppKit,
    getJettonWalletAddress,
    getSelectedWallet,
  } from '@ton/appkit';

  async function fetchJettonWalletAddress(
    /** Initialized AppKit instance */
    kit: AppKit,
    /** Jetton master (minter) contract address */
    jettonAddress: string,
  ) {
    const selectedWallet = getSelectedWallet(kit);
    const address = await getJettonWalletAddress(kit, {
      jettonAddress,
      // TON wallet address of the jetton holder
      ownerAddress: selectedWallet?.getAddress() ?? '<TON_WALLET_ADDRESS>',
    });
    console.log('Jetton wallet address:', address);
  }
  ```
</CodeGroup>

## Balance

Similar to Toncoin balance checks, [discrete one-off checks](#on-demand-balance-check) have limited value on their own and [continuous monitoring](#continuous-balance-monitoring) should be used for UI display.

Unlike Toncoin, the balance units and decimal places vary between jettons — use the `decimals` field from the [jetton's metadata](#metadata) to interpret raw amounts correctly.

USDT has a decimal precision of 6, meaning that the fractional balance string `'0.1'` represents a balance of 0.1 USDT, or 100000 micro USDT (raw units).

### On-demand balance check

<Aside type="caution">
  Do not store the balance check results anywhere in the application state, as they become outdated quickly. For UI purposes, do [continuous balance monitoring](#continuous-balance-monitoring).
</Aside>

#### Single jetton

Check the balance of a specific jetton for the connected TON wallet or an arbitrary address:

<CodeGroup>
  ```tsx title="React" icon="react" 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 {
    useJettonBalanceByAddress,
    useAddress,
  } from '@ton/appkit-react';

  export const JettonBalanceCard = ({ jettonAddress }) => {
    const ownerAddress = useAddress();
    const {
      data: balance,
      isLoading,
      error,
    } = useJettonBalanceByAddress({
      // TON wallet address of the jetton holder
      ownerAddress: ownerAddress ?? '<TON_WALLET_ADDRESS>',

      // Jetton master (minter) contract address
      jettonAddress,

      // Jetton decimals to calculate raw unit amounts
      jettonDecimals: 6,
    });

    if (isLoading) {
      return <div>Loading...</div>;
    }

    if (error) {
      return <div>Error: {error.message}</div>;
    }

    return <div>Jetton balance: {balance ?? '0'}</div>;
  };
  ```

  ```ts title="TypeScript" icon="globe" 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 {
    type AppKit,
    getJettonBalance,
    getSelectedWallet,
  } from '@ton/appkit';

  async function fetchJettonBalance(
    /** Initialized AppKit instance */
    kit: AppKit,
    /** Jetton master (minter) contract address */
    jettonAddress: string,
    /** Jetton decimals to calculate raw unit amounts */
    jettonDecimals: number = 6,
  ) {
    const selectedWallet = getSelectedWallet(kit);
    const balance = await getJettonBalance(kit, {
      jettonAddress,
      // TON wallet address of the jetton holder
      ownerAddress: selectedWallet?.getAddress() ?? '<TON_WALLET_ADDRESS>',
    });
    console.log('Jetton balance:', balance ?? '0');
  }
  ```
</CodeGroup>

#### All jettons

Retrieve every jetton held by the connected TON wallet or an arbitrary address:

<CodeGroup>
  ```tsx title="React" icon="react" 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 {
    useJettonsByAddress,
    useAddress,
    // Helper function targeting the connected wallet
    useJettons,
  } from '@ton/appkit-react';

  export const JettonListByAddress = () => {
    const address = useAddress();
    const {
      data: jettons,
      isLoading,
      error,
    } = useJettonsByAddress({
      // TON wallet address of the jetton holder
      address: address ?? '<TON_WALLET_ADDRESS>',
    });

    // Alternatively, query the connected wallet directly
    // const { data: jettons, isLoading, error } = useJettons();

    if (isLoading) {
      return <div>Loading...</div>;
    }

    if (error) {
      return <div>Error: {error.message}</div>;
    }

    return (
      <div>
        <p>Jettons</p>
        <ul>
          {jettons?.jettons.map((jetton) => (
            <li key={jetton.walletAddress}>
              {jetton.info.name}: {jetton.balance ?? '0'}
            </li>
          ))}
        </ul>
      </div>
    );
  };
  ```

  ```ts title="TypeScript" icon="globe" 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 {
    type AppKit,
    getJettonsByAddress,
    getSelectedWallet,
    // Helper function targeting the connected wallet
    getJettons,
  } from '@ton/appkit';

  async function fetchJettonsByAddress(
    /** AppKit instance */
    kit: AppKit,
  ) {
    const selectedWallet = getSelectedWallet(kit);
    const response = await getJettonsByAddress(kit, {
      address: selectedWallet?.getAddress() ?? '<TON_WALLET_ADDRESS>',
    });

    // Alternatively, query the connected wallet directly
    // const response = await getJettons();

    console.log('Jettons by address:', response.jettons.length);
    response.jettons.forEach((j) =>
      console.log(`- ${j.info.name}: ${j.balance ?? '0'}`),
    );
  }
  ```
</CodeGroup>

### Continuous balance monitoring

Poll the balance at regular intervals to keep the displayed value up to date. Use an appropriate interval based on UX requirements — shorter intervals provide fresher data but increase API usage.

Modify the following example according to the application logic:

<CodeGroup>
  ```tsx title="React" icon="react" 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 {
    useJettonBalanceByAddress,
    useAddress,
  } from '@ton/appkit-react';

  export const JettonBalanceCard = ({ jettonAddress }) => {
    const ownerAddress = useAddress();
    const {
      data: balance,
      isLoading,
      error,
      refetch,
    } = useJettonBalanceByAddress({
      // TON wallet address of the jetton holder
      ownerAddress: ownerAddress ?? '<TON_WALLET_ADDRESS>',

      // Jetton master (minter) contract address
      jettonAddress,
    });

    if (isLoading) {
      return <div>Loading...</div>;
    }

    if (error) {
      return (
        <div>
          <p>Error: {error.message}</p>
          <button onClick={() => refetch()}>Try again</button>
        </div>
      );
    }

    return <div>Jetton balance: {balance ?? '0'}</div>;
  };
  ```

  ```ts title="TypeScript" icon="globe" expandable 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"]}}
  // Not runnable: implement the updateUI()
  import {
    type AppKit,
    getJettonBalance,
    getSelectedWallet,
  } from '@ton/appkit';

  /**
   * Starts the monitoring of a specific jetton balance for the connected wallet,
   * calling `onBalanceUpdate()` every `intervalMs` milliseconds
   *
   * @returns a function to stop monitoring
   */
  export function startJettonBalanceMonitoring(
    kit: AppKit,
    jettonAddress: string,
    onBalanceUpdate: (balance: string) => void,
    intervalMs: number = 10_000,
  ): () => void {
    let isRunning = true;

    const poll = async () => {
      while (isRunning) {
        const selectedWallet = getSelectedWallet(kit);
        if (selectedWallet) {
          const balance = await getJettonBalance(kit, {
            jettonAddress,
            // TON wallet address of the jetton holder
            ownerAddress: selectedWallet?.getAddress() ?? '<TON_WALLET_ADDRESS>',
          });
          onBalanceUpdate(balance);
        }
        await new Promise((resolve) => setTimeout(resolve, intervalMs));
      }
    };

    // Start monitoring
    poll();

    // Return a cleanup function to stop monitoring
    return () => {
      isRunning = false;
    };
  }

  // Usage
  const stopMonitoring = startJettonBalanceMonitoring(
    kit,
    // Jetton master (minter) contract address
    // E.g., USDT on TON mainnet:
    'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs',
    // The updateUI() function is exemplary and should be replaced by
    // an app function that refreshes the state of the balance displayed
    // in the interface
    (balance) => updateUI(balance),
  );

  // Stop monitoring once it is no longer needed
  stopMonitoring();
  ```
</CodeGroup>

## Transfers

<Aside type="danger" title="Funds at risk">
  Each jetton stores the `decimals` parameter in its [metadata](#metadata). Transferring without accounting for decimals can result in sending drastically more or fewer tokens than intended.

  Mitigation: Verify the correct `decimals` value before calculating transfer amounts. For USDTs, the decimals value is 6.
</Aside>

Before making a transfer, make sure there is enough Toncoin in the balance to cover the [fees](/foundations/fees).

Modify the following examples according to the application logic:

<CodeGroup>
  ```tsx title="React (component)" icon="react" 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"]}}
  // Pre-built UI component for sending jetton transactions by clicking a button.
  // It handles success and error states while being customizable.
  import { SendJettonButton } from '@ton/appkit-react';

  export const SendJetton = () => {
    // For example: 'UQ...'
    const recipientAddress = '<TON_WALLET_ADDRESS>';
    // For example, '0.1' or '1' jetton
    const jettonAmount = '<FRACTIONAL_JETTON_AMOUNT>';
    // For example, 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs'
    const jettonAddress = '<JETTON_MINTER_ADDRESS>';

    return (
      <SendJettonButton
        // New owner of the sent jettons
        recipientAddress={recipientAddress}

        // Jetton amount in fractional units
        amount={jettonAmount}

        // What kind of jettons to send
        jetton={{
          // Jetton master (minter) contract address
          address: jettonAddress,

          // Short ticker name
          symbol: 'USDT',

          // Jetton decimals to calculate raw unit amounts
          // For example, USDT defaults to 6, while Toncoin to 9:
          decimals: 6,
        }}

        // (optional) Comment
        comment="Hello from AppKit!"

        // (optional) Add custom button title
        text="Send some jetton"

        // (optional) Handle successes
        onSuccess={(result) => console.log('Transaction sent:', result)}

        // (optional) Handle errors
        onError={(error) => console.error('Transaction failed:', error)}

        // (optional) Add custom CSS classes
        className=''

        // (optional) When set to `true`, the button is disabled
        disabled={false}
      />
    );
  };
  ```

  ```tsx title="React (hook)" icon="react" 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 { useTransferJetton } from '@ton/appkit-react';

  export const SendJetton = ({ recipientAddress, jettonAddress }) => {
    const { mutate: transfer, isPending, error, data } = useTransferJetton();

    const handleTransfer = () => {
      transfer({
        // New owner of the sent jettons.
        // For example: 'UQ...'
        recipientAddress,

        // Jetton amount string in fractional units.
        // For example, '0.1' or '1' jetton
        amount: '<FRACTIONAL_JETTON_AMOUNT>',

        // Jetton master (minter) contract address.
        jettonAddress,

        // Jetton decimals to calculate raw unit amounts.
        // For example, USDT defaults to 6, while Toncoin to 9:
        jettonDecimals: 6,

        // (optional) Comment string. Defaults to none if not provided.
        comment: 'Hello from AppKit!',
      });
    };

    return (
      <div>
        <button onClick={handleTransfer} disabled={isPending}>
          {isPending ? 'Transferring...' : 'Transfer jetton'}
        </button>
        {error && <div>Error: {error.message}</div>}
        {data && (
          <div>
            <p>Transfer successful: {data.boc}</p>
          </div>
        )}
      </div>
    );
  };
  ```

  ```ts title="TypeScript" icon="globe" 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 {
    type AppKit,
    type Base64String,
    // Single-call transfer
    transferJetton,
    // Two-step transfer: create a transaction object separately from sending it
    createTransferJettonTransaction,
    sendTransaction,
  } from '@ton/appkit';

  async function sendJetton(
    /** Initialized AppKit instance */
    kit: AppKit,
    /** Recipient's TON wallet address as a string */
    recipientAddress: string,
    /**
     * Jetton amount string in fractional units
     * E.g., '0.1' or '1' jetton
     */
    amount: string,
    /** Jetton decimals to calculate raw unit amounts */
    jettonDecimals: number = 6,
    /** Jetton master (minter) contract address */
    jettonAddress: string,
    /** Optional comment string */
    comment?: string,
  ) {
    // Sign and send via TON Connect
    const result = await transferJetton(kit, {
      recipientAddress,
      amount,
      jettonDecimals,
      jettonAddress,
      ...(comment && { comment }),
    });
    console.log('Transaction sent:', result.boc);

    // Alternatively, build the transaction first with createTransferJettonTransaction,
    // then pass the resulting object to the sendTransaction function.
  }
  ```
</CodeGroup>

## Next steps

<Columns cols={2}>
  <Card title="Work with NFTs" icon="image" horizontal="true" href="/ecosystem/appkit/nfts" />
</Columns>

## See also

Jettons:

* [Jettons overview](/standard/tokens/jettons/overview)
* [Jetton transfers](/standard/tokens/jettons/transfer)
* [Token metadata and decimals](/standard/tokens/metadata#decimals)

General:

* [Transaction fees](/foundations/fees)
* [AppKit overview](/ecosystem/appkit/overview)
* [TON Connect overview](/ecosystem/ton-connect)
