> 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

[Many to Many Transfer](https://j.tools/en/tools/many-to-many) moves SOL or one SPL token across paired wallets. Each sender you import pays its own matched recipient an explicit amount, and the whole list runs as one batch. Every transaction is signed in your browser, so the sender keys never touch a server. Think of it as a matrix payout: sender row one goes to recipient row one, row two to row two, and so on down the list. If you are new to the asset side of this, the [Glossary](/getting-started/glossary.md) covers terms like SPL and rent.

{% 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 %}

## When to use this

* You have many source wallets and each needs to fund its own specific recipient in a single run.
* You are distributing SOL or one SPL token across paired sender-to-recipient mappings.
* You already hold a list of sender private keys plus a matching list of recipient addresses.

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 to act as operator ([how to connect](/getting-started/quick-start.md)). It selects the asset and broadcasts; the imported senders sign their own transfers.
* 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 %}

### Select the wallet source

Connect and choose your operator wallet at the top of the tool. This wallet drives the batch; it does not pay the recipients.
{% 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 sign more than one thing in a single step, for example creating a token and its metadata together. Phantom can show a caution banner for these multi-step transactions. The banner is expected here and does not mean something is wrong. Read what you are signing, then approve.
{% endhint %}

## The options, explained

| Field                   | What it does                                                                                                                         |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| 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: 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.                                                                                 |

{% hint style="info" %}
The platform fee is charged inside each sender's own transaction as a second transfer to the platform wallet, and the server verifies it on broadcast, so it cannot be stripped. Cost scales linearly with the number of pairs, since each pair is its own signed transaction. See the live fee summary in the tool and the [Fee schedule](/reference/fee-schedule.md) for the current amount.
{% endhint %}

## If something goes wrong

Some rows skip on purpose rather than failing on-chain. That is the runner protecting your funds.

* **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.
* **Confirmation timeout (`CONFIRM_TIMEOUT`).** A transaction did not confirm within the time limit and is marked failed. Use **Keep only failed** and retry.
* **Batch too large.** A single run is capped at a maximum number of transfers. Split a bigger list into more than one batch.

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

## FAQ

<details>

<summary>Do my sender private keys leave the browser?</summary>

No. Each key is used only in your browser to sign its own transfer, and they are never sent to a server. The operator wallet you connect at the top is what broadcasts the signed transactions.

</details>

<details>

<summary>How are senders matched to recipients?</summary>

By position. The first sender pays the first recipient, the second pays the second, and so on. Keep both lists the same length and in the same order, or the leftover rows stay unpaired and cannot send.

</details>

<details>

<summary>Can I move both SOL and a token in the same run?</summary>

No. A batch moves one asset. Choose SOL, or choose SPL and pick a single mint for the whole run. Run a second batch for the other asset.

</details>

<details>

<summary>Why was a row skipped instead of sent?</summary>

The runner skips rows it knows would fail or strand funds: senders below the rent-exempt minimum after sending, senders short on SOL for the amount and fees, zero-amount rows, and unmatched rows. The status column shows the reason for each one.

</details>

<details>

<summary>Does it handle Token-2022 tokens?</summary>

Yes. The runner detects whether the mint is a classic SPL token or Token-2022 from the mint's owning program and transfers accordingly.

</details>

## Related tools

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

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

{% content-ref url="/pages/nHTziE15NKeVLAQMnxv5" %}
[Relay Transfer](/tools/wallets/relay-transfer.md)
{% endcontent-ref %}

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

{% hint style="warning" %}
**About multi-wallet mode.** This mode works with private keys you import into the page. Only use wallets you can treat as disposable, and rotate them after you are done. For everything else, J Tools stays non-custodial: you sign in your own wallet, and we never ask for its key.
{% 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.
