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

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

</AgentInstructions>

# Jettons payments processing

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

Processing jetton payments requires understanding TON's sharded token architecture. Unlike single-contract token systems, each jetton type consists of a master contract and individual wallet contracts for each holder.

<Aside type="note">
  Jettons are fungible tokens on TON. Each jetton has a master contract (minter) and separate wallet contracts for every holder. Read more in [How Jettons Work](/standard/tokens/jettons/how-it-works).
</Aside>

<Aside type="caution">
  Jetton processing is security-critical. Incorrect validation of jetton wallet addresses or transfer notifications can lead to accepting fake tokens or crediting wrong amounts.
</Aside>

## Key concepts

Before implementing jetton payment processing, understand these core concepts:

**Jetton architecture**: Each jetton type has one master contract that stores metadata and total supply. Each address holding the jetton has a separate jetton wallet contract at a deterministic address derived from the master contract and owner address.

**Transfer flow**: Jetton transfers involve multiple messages. A user sends a `transfer` message to their jetton wallet, which sends an `internal_transfer` to the recipient's jetton wallet, which then sends a `transfer_notification` to the recipient's address if `forward_ton_amount > 0`.

<Aside type="caution">
  Jetton transfers are considered successful only when the recipient receives `transfer_notification`. Services must set `forward_ton_amount` to at least 0.000000001 TON (1 nanoton) when sending tokens to trigger notifications. Without this, transfers won't be compliant and may not be processed by exchanges and other services.
</Aside>

**Security model**: Always validate that jetton wallets belong to the expected master contract. Anyone can deploy fake jetton wallet contracts with arbitrary balances.

This article covers processing jetton deposits using transfer notifications. All approaches require maintaining an allowlist of trusted jetton master contracts.

For architectural patterns and deposit methods comparison, see [Toncoin processing](/payments/toncoin).

## Processing deposits

<Aside type="danger" title="Funds at risk">
  Skipping any validation step or changing their order can lead to incorrect deposit processing and potential loss of funds.
</Aside>

### Setup

Processing jetton deposits requires:

* **Allowlist of trusted jetton masters**: List of jetton master contract addresses to accept
* **Deposit wallet address**: Service wallet (e.g., wallet v4 or v5)

### Initial configuration

1. For each allowlisted jetton master, derive the jetton wallet address for the deposit wallet using the master contract's `get_wallet_address()` method
2. Store the mapping of `jetton master` → `jetton wallet` → `deposit wallet` in the database
3. Begin monitoring transactions to the deposit wallet address

### Processing incoming transactions

When a transaction arrives at the deposit wallet:

1. Check that `tx.in_msg.source` matches a known jetton wallet for this deposit wallet
2. Verify the master → jetton wallet relationship:
   * Call `get_wallet_address(deposit-wallet)` on the master contract
   * Confirm the returned address matches the sender
3. Verify there are no outgoing messages (`tx.out_msgs.length === 0`)
4. Parse the message body:
   * Check the opcode (first 32 bits of `tx.in_msg.body`) equals `0x7362d09c` (transfer\_notification)
   * Extract `query_id`, `amount`, `sender`, and `forward_payload` [according to TL-B](/standard/tokens/jettons/api)
5. Verify the amount matches the expected value

### Crediting user accounts

After validation, extract deposit information:

* For [invoice-based deposits][inv-dep]: Parse the invoice ID from `forward_payload`, match it against the database, and credit the corresponding user account.
* For [address-based deposits][add-dep]: Match the `deposit-wallet` address against the database and credit the user account.

<Aside type="note">
  Not production-ready code, use only for educational purposes:

  * [Invoice-based jetton deposits][inv-dep]
  * [Unique address jetton deposits][add-dep]
</Aside>

[inv-dep]: https://github.com/ton-org/docs-examples/blob/jetton-processing-only/guidebook/jetton-processing/src/deposits/jetton-invoices.ts

[add-dep]: https://github.com/ton-org/docs-examples/blob/jetton-processing-only/guidebook/jetton-processing/src/deposits/jetton-unique-addresses.ts

## Security considerations

### Master-wallet verification

Never trust jetton wallet addresses without verification. Always perform these checks:

1. Get the jetton master address from the allowlist
2. Call `jetton_master.get_wallet_address(owner_address)`
3. Verify the returned address matches the jetton wallet that sent the notification

### Transfer notification validation

When processing deposits via `transfer_notification`:

* Verify the opcode is exactly `0x7362d09c`
* Check the sender address is an expected jetton wallet
* Extract `amount` in base units (not decimal)
* Validate the `sender` field against expected user addresses
* Parse `forward_payload` carefully—it may be malformed
* Check for bounce indicators (single outgoing message back to sender)

### Fake jetton detection

Attackers can deploy jettons with identical names, symbols, and images:

* Always verify the jetton master address against the allowlist
* Never trust metadata (name, symbol, image) for authentication
* Display the master contract address in admin interfaces
* Implement a manual approval workflow for adding new jettons

## Common attack patterns

### Fake jetton wallets

**Attack**: Attacker deploys a contract claiming to be a jetton wallet with an inflated balance.

**Mitigation**: Verify the master-wallet relationship by calling `get_wallet_address()` on the master contract.

### Invoice ID reuse

**Attack**: User attempts to reuse a settled invoice identifier.

**Mitigation**: Mark invoices as used after the first successful deposit.

### Master contract spoofing

**Attack**: Deploying a fake master contract that validates the attacker's fake jetton wallets.

**Mitigation**: Maintain a strict allowlist of trusted master contracts and verify all jetton wallets against it.

## Implementation checklist

Before enabling jetton processing in production:

### Testing

1. Deploy and test on testnet with real user scenarios
2. Verify master-wallet relationships for all allowlisted jettons
3. Test with fake jetton wallets to confirm rejection
4. Validate transfer notification parsing with various payload formats
5. Test bounce detection and handling
6. Test invoice ID collision and reuse scenarios
7. Test full flow: deposit → credit → withdrawal → confirmation
