---
title: Payment with Memo
description: Learn how to attach invoice IDs or notes to a payment.
---

Solana's memo program lets you attach invoice numbers, order IDs, or custom
references to any payment. These memos are permanently recorded onchain and
visible in transaction logs, making it easy to match payments to your internal
systems.

## How It Works

The Memo program writes text to the transaction's logs. These logs are indexed
by explorers and RPC providers, making memos searchable for payment
reconciliation.

<Callout>
  See [How Payments Work on Solana](/docs/payments/how-payments-work) for core
  payment concepts.
</Callout>

Adding a memo requires building instructions directly, which gives you control
over what's included in the transaction.

The steps below show the core flow. See the [Demo](#demo) for complete runnable
code.

<ScrollyCoding>

## !!steps Import Memo Program

Import `getAddMemoInstruction` from `@solana-program/memo` to create memo
instructions.

<CodePlaceholder title="Payment with Memo" />

```ts !! title="Payment with Memo"
// !focus
import { getAddMemoInstruction } from "@solana-program/memo";
```

## !!steps Create Transfer Instruction

Create the token transfer instruction specifying the source ATA, destination
ATA, authority (signer), and amount in base units.

<CodePlaceholder title="Payment with Memo" />

```ts !! title="Payment with Memo"
import { getAddMemoInstruction } from "@solana-program/memo";

// !focus(1:6)
const transferInstruction = getTransferInstruction({
  source: senderAta,
  destination: recipientAta,
  authority: sender.address,
  amount: 250_000n // adjusted for the mint's decimals
});
```

## !!steps Create Memo Instruction

Create a memo instruction with a message. This message will be visible in the
program logs of the transaction.

<CodePlaceholder title="Payment with Memo" />

```ts !! title="Payment with Memo"
import { getAddMemoInstruction } from "@solana-program/memo";

const transferInstruction = getTransferInstruction({
  source: senderAta,
  destination: recipientAta,
  authority: sender.address,
  amount: 250_000n
});

// !focus(1:3)
const memoInstruction = getAddMemoInstruction({
  memo: "Payment for services rendered - Invoice #12345"
});
```

## !!steps Send Transaction with Memo

Combine the transfer and memo instructions in a single transaction.

<CodePlaceholder title="Payment with Memo" />

```ts !! title="Payment with Memo"
import { getAddMemoInstruction } from "@solana-program/memo";

const transferInstruction = getTransferInstruction({
  source: senderAta,
  destination: recipientAta,
  authority: sender.address,
  amount: 250_000n
});

const memoInstruction = getAddMemoInstruction({
  memo: "Payment for services rendered - Invoice #12345"
});

// !focus(1:3)
const {
  context: { signature }
  // !mark
} = await client.sendTransaction([transferInstruction, memoInstruction]);
```

## !!steps View Memo in Transaction Logs

After the transaction confirms, fetch it to view the memo in the logs. The memo
appears as a log message from the Memo program.

<CodePlaceholder title="Payment with Memo" />

```sh title="Example Transaction Logs"
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [1]",
"Program log: Instruction: Transfer",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1682 of 200000 compute units",
"Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success",
"Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr invoke [1]",
# !mark
'Program log: Memo (len 46): "Payment for services rendered - Invoice #12345"',
"Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr consumed 18097 of 198318 compute units",
"Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr success",
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success"
```

```ts !! title="Payment with Memo"
import { getAddMemoInstruction } from "@solana-program/memo";

const transferInstruction = getTransferInstruction({
  source: senderAta,
  destination: recipientAta,
  authority: sender.address,
  amount: 250_000n
});

const memoInstruction = getAddMemoInstruction({
  memo: "Payment for services rendered - Invoice #12345"
});

const {
  context: { signature }
} = await client.sendTransaction([transferInstruction, memoInstruction]);

// !focus(1:9)
const transaction = await client.rpc
  .getTransaction(signature, {
    encoding: "jsonParsed",
    maxSupportedTransactionVersion: 0
  })
  .send();

console.log("Transaction logs with Memo:");
console.log(transaction?.meta?.logMessages);
```

</ScrollyCoding>

### Demo

<CodeTabs flags="r">

```ts !! title="Demo"
// !collapse(1:16) collapsed
// Click ">" icon on left to expand demo imports
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import type { KeyPairSigner } from "@solana/kit";
import { signer } from "@solana/kit-plugin-signer";
import { solanaLocalRpc } from "@solana/kit-plugin-rpc";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
  getCreateAssociatedTokenInstructionAsync,
  getInitializeMintInstruction,
  getMintSize,
  TOKEN_2022_PROGRAM_ADDRESS,
  findAssociatedTokenPda,
  getMintToInstruction,
  getTransferInstruction
} from "@solana-program/token-2022";
// !mark
import { getAddMemoInstruction } from "@solana-program/memo";

// Generate keypairs for sender and recipient
const sender = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();

console.log("Sender Address:", sender.address);
console.log("Recipient Address:", recipient.address);

// Demo Setup: Create client, mint account, token accounts, and fund with initial tokens
const { client, mint } = await demoSetup(sender, recipient);

console.log("\nMint Address:", mint.address);

// Derive the Associated Token Accounts addresses (ATAs) for sender and recipient
const [senderAta] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: sender.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

const [recipientAta] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: recipient.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

console.log("Sender Token Account:", senderAta.toString());
console.log("Recipient Token Account:", recipientAta.toString());

// =============================================================================
// Token Payment with Memo Demo
// =============================================================================

// Create instruction to transfer tokens from sender to recipient
// Transferring 250,000 base units = 0.25 tokens (with 6 decimals)
const transferInstruction = getTransferInstruction({
  source: senderAta,
  destination: recipientAta,
  authority: sender.address,
  amount: 250_000n // 0.25 tokens
});

// Create instruction to add a memo to the transaction
// !mark(1:3)
const memoInstruction = getAddMemoInstruction({
  memo: "Payment for services rendered - Invoice #12345"
});

// Send transaction with both transfer and memo
const {
  context: { signature }
  // !mark
} = await client.sendTransaction([transferInstruction, memoInstruction]);

console.log("\n=== Token Payment with Memo Complete ===");
console.log("Transaction Signature:", signature.toString());

// Fetch final token account balances
const senderBalance = await client.rpc.getTokenAccountBalance(senderAta).send();
const recipientBalance = await client.rpc
  .getTokenAccountBalance(recipientAta)
  .send();

console.log("\nSender Token Account Balance:", senderBalance.value.uiAmount);
console.log(
  "Recipient Token Account Balance:",
  recipientBalance.value.uiAmount
);

// Fetch transaction details to view the memo in the logs
const transaction = await client.rpc
  .getTransaction(signature, {
    encoding: "jsonParsed",
    maxSupportedTransactionVersion: 0
  })
  .send();

console.log("\nTransaction logs with Memo:");
console.log(transaction?.meta?.logMessages);

// =============================================================================
// Demo Setup Helper Function
// =============================================================================
// !collapse(1:1000) collapsed

/**
 * Sets up for a token transfer with memo demo:
 * - Creates @solana/kit client
 * - Airdrops SOL to sender for transaction fees
 * - Generates mint keypair and creates/initializes mint account
 * - Creates associated token accounts for sender and recipient
 * - Mints initial tokens to sender
 *
 * @param sender - The sender's keypair (will be funded and used as mint authority)
 * @param recipient - The recipient's keypair
 * @returns Returns client instance and mint address
 */
async function demoSetup(sender: KeyPairSigner, recipient: KeyPairSigner) {
  // Create @solana/kit client pointing to local validator
  const client = createClient().use(signer(sender)).use(solanaLocalRpc());

  // Fund sender with SOL for transaction fees
  await client.airdrop(sender.address, lamports(1_000_000_000n));

  // Generate keypair to use as address of mint
  const mint = await generateKeyPairSigner();

  // Get default mint account size (in bytes), no extensions enabled
  const space = BigInt(getMintSize());

  // Get minimum balance for rent exemption
  const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();

  // Instruction to create new account for mint (token program)
  // Invokes the system program
  const createAccountInstruction = getCreateAccountInstruction({
    payer: sender,
    newAccount: mint,
    lamports: rent,
    space,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  });

  // Instruction to initialize mint account data
  // Invokes the token 2022 program
  const initializeMintInstruction = getInitializeMintInstruction({
    mint: mint.address,
    decimals: 6,
    mintAuthority: sender.address
  });

  // Derive sender's associated token account address (ATA)
  const [senderAta] = await findAssociatedTokenPda({
    mint: mint.address,
    owner: sender.address,
    tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
  });

  // Create instruction for sender's ATA
  const createSenderAtaInstruction =
    await getCreateAssociatedTokenInstructionAsync({
      payer: sender,
      mint: mint.address,
      owner: sender.address,
      tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
    });

  // Create instruction for recipient's ATA
  const createRecipientAtaInstruction =
    await getCreateAssociatedTokenInstructionAsync({
      payer: sender,
      mint: mint.address,
      owner: recipient.address,
      tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
    });

  // Create instruction to mint initial tokens to sender
  const mintToInstruction = getMintToInstruction({
    mint: mint.address,
    token: senderAta,
    mintAuthority: sender.address,
    amount: 1_000_000n // Mint 1.00 tokens (1,000,000 base units with 6 decimals)
  });

  // Combine all instructions and send
  const setupInstructions = [
    createAccountInstruction, // Create mint account
    initializeMintInstruction, // Initialize mint
    createSenderAtaInstruction, // Create sender's ATA
    createRecipientAtaInstruction, // Create recipient's ATA
    mintToInstruction // Mint tokens to sender
  ];

  // Send transaction
  await client.sendTransaction(setupInstructions);

  return {
    client,
    mint
  };
}
```

</CodeTabs>
