> For the complete documentation index, see [llms.txt](https://docs.j.tools/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.j.tools/tools/wallets/many-to-many.md).

# Many-to-Many Transfers: Paired Wallet Sends

[Many to Many Transfer](https://j.tools/en/tools/many-to-many) moves SOL or one SPL token across paired wallets, where each sender you import pays its own matched recipient an explicit amount. The whole list runs as one batch, and every transfer is signed in your own browser, so the sender keys never touch a server. Think of it as a paired payout: sender row one goes to recipient row one, row two to row two, straight down the list.

## What it is

Many to Many Transfer is a paired-payout tool. You bring two lists, a column of sender private keys and a column of recipient addresses, and the tool pairs them by position. Sender\[i] pays recipient\[i] the amount you set for that row. It handles native SOL and a single SPL token (classic or Token-2022), and it runs the entire mapping as one coordinated batch instead of a string of manual sends.

The distinguishing trait is the one-to-one pairing. Other batch tools fan out from a single wallet or sweep into a single wallet. Here, each row is its own independent sender paying its own recipient, all triggered together. If you are new to the asset side of this, the [Glossary](/getting-started/glossary.md) covers terms like SPL and rent.

## Why use this tool

Doing this by hand means opening each sender wallet, copying a recipient address, typing an amount, signing, waiting for confirmation, and repeating that for every pair. For a dozen wallets that is tedious. For a hundred it is a long evening and a real chance of pasting the wrong address into the wrong row.

Here you set the mapping up once and send it as a batch. Rows that would strand funds or fail on-chain are flagged and skipped before they cost you anything, which is the part that saves money on a long list.

## How it works (under the hood)

When you run the batch, the tool builds a separate transaction for each pair. For a SOL row, that transaction carries the transfer from that sender to its recipient plus a second small transfer that pays the platform fee. For an SPL row, it resolves the token accounts on both sides, creates the recipient's token account if it does not exist yet, and moves the token amount, again alongside the fee transfer. Whether the mint is classic SPL or Token-2022 is detected from its owning program, and the transfer is routed accordingly.

Every transaction is signed locally by that row's own sender key inside your browser. The imported private keys are used only to sign and are never sent anywhere. The wallet you connect at the top pays nobody and signs nothing. It selects the asset and labels the run; your browser posts the signed transactions to the broadcast endpoint itself. Because the fee transfer is baked into each signed transaction and the server checks for it on broadcast, the fee cannot be stripped out after signing.

Before broadcasting, the runner refetches each sender's live balance, drops any row that can no longer cover its amount plus fees, and only then sends. Cost grows with the number of pairs, since each pair is its own signed transaction with its own fee.

## When to use it

* You have many source wallets and each one needs to fund its own specific recipient in a single run.
* You are distributing SOL or one SPL token across a fixed sender-to-recipient mapping.
* You already hold a list of sender private keys plus a matching list of recipient addresses, in the same order.
* You want per-row amounts (a Max sweep on some rows, a fixed number on others) rather than one identical amount everywhere.

If you want one source wallet sending to many recipients, use [Multi Sender](/tools/wallets/multi-sender.md). If you want many wallets sweeping into one, use [Batch Collector](/tools/wallets/batch-collector.md). For SPL mode it helps to know the difference between classic SPL and [SPL vs Token-2022](/concepts/spl-vs-token2022.md), since the transfer path changes.

## Before you start

* A connected wallet is optional ([how to connect](/getting-started/quick-start.md)). It never signs and never pays; it only labels the run so the commission can be attributed. What the batch actually needs is a working RPC connection, which the page sets up for you.
* Your sender private keys, ready to import (base58, base64, or byte-array). Keys are used only in the browser.
* A matching list of recipient public addresses. The two lists pair by position.
* For SPL mode, the token mint you want to move. Pick it with the built-in token selector.
* Enough SOL in each sender to cover its amount, the platform fee, and the network base fee. SPL recipients that need a new token account add a small one-time rent on top.

{% hint style="warning" %}
Pairing is strictly by order. Sender row one maps to recipient row one. Extra rows on either side stay unmatched and cannot send, so keep the two lists the same length and in the same order.
{% endhint %}

## Step by step

{% stepper %}
{% step %}

### Connect, or don't

You can connect a wallet at the top of the tool. It does not sign and does not pay recipients, it only attributes the run. Skip it and the batch still works.
{% endstep %}

{% step %}

### Pick the asset

Choose SOL for native transfers, or switch to SPL and pick a token with the selector. The whole batch moves one asset.
{% endstep %}

{% step %}

### Import senders, then recipients

Use **Import senders** to paste the private keys, then **Import recipients** to paste the addresses. They pair in order, so sender\[i] pays recipient\[i]. Each sender signs only its own transfer.
{% endstep %}

{% step %}

### Set the amounts

Use bulk mode to fill every row at once: **Max** sends each sender's full spendable balance, **Fixed** sets one amount per row, and **Percentage** sends a share of each sender's balance. There is no Apply button; the rows fill live. Hand-edit any row to override it, and it stays locked until you change the bulk control again.
{% endstep %}

{% step %}

### Review the preview and summary

Check the Pairs table (from, to, each sender's balance, amount, and status) and the Summary panel (platform fee for the ready count, estimated network fee, and total to send). Fix anything flagged before running.
{% endstep %}

{% step %}

### Send the batch

Click the **Send** button (its label shows the number of pairs). The runner refetches balances, drops rows that cannot send, builds and signs each sender's transaction in the browser, then broadcasts through the server. Watch per-row status with Solscan links, and use **Keep only failed** to retry just the rows that did not go through.
{% endstep %}
{% endstepper %}

[**Open Many to Many Transfer in the app →**](https://j.tools/en/tools/many-to-many)

{% hint style="info" %}
**About wallet warnings.** Some tools bundle several instructions into one transaction, for example creating a token and its metadata together. Phantom can show a caution banner for these transactions. The banner is expected here and does not mean something is wrong. Read what you are signing, then approve.
{% endhint %}

## The options, explained

* **Token type:** SOL or SPL. Decides whether the whole batch moves native SOL or one token.
* **Token mint:** Required for SPL. The single mint moved for every pair, picked with the token selector.
* **Sender key (from):** The private key that signs that row's transfer in the browser. Accepts base58, base64, or byte-array.
* **Recipient (to):** The public address that the matched sender pays.
* **Amount:** The amount for that pair, in SOL units (SOL mode) or token units (SPL mode).
* **Bulk mode:** Auto-fills every row at once with Max, Fixed, or Percentage. Fills live, no Apply button. Edited rows lock until you change the control.
* **Platform fee and wallet:** The per-transfer fee and its destination, charged on-chain inside each sender's own transaction.
* **RPC endpoint:** The endpoint used to build and confirm transactions.

## Fees and costs

{% hint style="warning" %}
**About fees.** Every action has two costs: the Solana **network fee** paid to validators, and the **J Tools platform fee**. The platform fee always shows in the app before you confirm, and nothing is charged until you sign. Fees can change over time, so trust the in-app summary rather than a number you saw once.
{% endhint %}

**Current platform fee: 0.001 SOL per transfer.** The amount is pinned to the tool's own constant, so every run charges the same: each sender's transaction carries a second transfer of exactly 0.001 SOL, and the broadcast endpoint rejects a batch whose fee transfer does not match.

| Cost                 | Amount                                             |
| -------------------- | -------------------------------------------------- |
| J Tools platform fee | 0.001 SOL per transfer                             |
| Solana network fee   | a small amount per transaction, paid to validators |

Example: 100 transfers cost 0.1 SOL in platform fees.

On top of the platform fee, each transfer pays Solana's own network base fee, which is 5000 lamports (0.000005 SOL) per signature and goes to validators, not to J Tools. In SPL mode, any recipient that does not yet have a token account for the mint adds a small one-time rent deposit to open that account. Because every pair is its own signed transaction, both the platform fee and the network fee scale linearly with the number of pairs you send. See the live fee summary in the tool and the [Fee schedule](/reference/fee-schedule.md) for the current amount.

## Security and custody

The sender private keys you import are used only inside your browser to sign each row's own transfer, and they are never uploaded. Still, treat any wallet whose key you paste into a web page as hot and disposable. Only import keys for wallets you are comfortable exposing this way, and empty or rotate them once the run is done. Never paste a key that guards funds you cannot afford to lose.

## Common mistakes and troubleshooting

Some rows skip on purpose rather than failing on-chain. That is the runner protecting your funds, and the status column shows the reason for each skipped row.

* **Rent dust skip (`M2M_RENT_DUST`).** In SOL mode, a row that would leave its sender with a tiny non-zero balance below Solana's rent-exempt minimum is skipped instead of failing. Send Max, or lower the amount so the sender either keeps enough or empties fully.
* **Not enough SOL (`M2M_INSUFFICIENT_SOL`).** The sender cannot cover its amount plus fees, or an SPL sender lacks the SOL for the fee and any new-account rent. Top that sender up. Zero-amount rows skip too.
* **Unmatched rows.** A recipient with no sender across from it cannot send, and a sender with no recipient shows as missing a recipient. Line the two lists up in the same order and keep them the same length.
* **Confirmation timeout (`CONFIRM_TIMEOUT`).** A transaction did not confirm within the time limit and is marked failed. Use **Keep only failed** and retry.
* **A long list slows down, it does not get rejected.** Rows are signed and broadcast in chunks of 100, and the broadcast endpoint allows 120 requests a minute per IP. There is no fixed transfer cap, so a very long run just takes longer and needs watching row by row.

For the full list, see the [Error codes reference](/reference/error-codes.md).

## Advanced tips

* **Validate both sides of the pairing.** Recipients are already public addresses, so they go straight into [Wallet Scope](/tools/utilities/wallet-scope.md). Senders come in as private keys, so derive their public addresses first and scan them in a second pass. A mispasted row is caught before it becomes a paid transfer; split lists longer than Wallet Scope's 500-address cap across passes.
* **Use Max for clean sweeps.** When you want each sender emptied to its recipient, Max accounts for fees and the rent minimum so you avoid the dust skip.
* **Split large mappings deliberately.** Nothing stops you pasting thousands of pairs, but a run you cannot watch is a run you cannot fix. Break long lists into batches that keep paired rows together rather than slicing a pair across two runs.

## Related tools

{% content-ref url="/pages/ABVX2mBQDoCv7DEdVmKp" %}
[Multi Sender and Airdrop](/tools/wallets/multi-sender.md)
{% endcontent-ref %}

{% content-ref url="/pages/7CPBHR61Y6akMdkeSBGW" %}
[Batch SOL and Token Collector](/tools/wallets/batch-collector.md)
{% endcontent-ref %}

{% content-ref url="/pages/tvk3KydrniyizApPkWZi" %}
[Wallet Scope: Bulk Wallet Analyzer](/tools/utilities/wallet-scope.md)
{% endcontent-ref %}

{% content-ref url="/pages/a7TACAPAW24OFOSbtgNw" %}
[Solana Wallet Generator](/tools/wallets/wallet-generator.md)
{% endcontent-ref %}

{% hint style="success" %}
**J Tools is non-custodial.** We never store or transmit your private keys and never ask for your seed phrase. Every transaction is signed in your own browser, and nothing about a key ever reaches our servers. A few multi-wallet tools do let you paste private keys for throwaway hot wallets, which stay in your browser tab and are used only to sign locally. Never paste a key tied to long-term holdings, and if a page ever asks for your seed phrase, stop and close it.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.j.tools/tools/wallets/many-to-many.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
