Navigate...

K

Distributions

Create and manage token distributions. The Distributions API handles sending tokens to multiple recipients in batched transactions, with full status tracking and cancellation support.

Overview

A distribution is the core operation of Multisender — sending tokens from one wallet to many recipients. There are two flows:Single-step flow (recommended for SDK): Call distribute() to create a distribution and receive transaction calldata in one call. Then sign and submit the transactions to the blockchain.Two-step flow (for review before execution): Create a draft with createDraft(), optionally edit with updateDraft() / replaceRecipients(), then call prepare() to generate calldata.Important: Multisender generates calldata but does not send transactions. You must sign and submit each transaction using your wallet or web3 library.

You must submit transactions yourself

Multisender does not send transactions on your behalf. distribute() returns calldata — pre-built transaction objects (to, data, value, gasLimit). You must sign and submit each transaction to the blockchain using your wallet or web3 library. The platform then tracks their on-chain status.

Recipients format

For distribute(): provide recipients as a CSV string ("address,amount\naddress,amount") or as an array of [address, amount] tuples. For createDraft(): provide as RecipientDto[] objects { address, amount } or reference a list by listId.

Key Concepts

Single-step flow

Call distribute() to create + prepare a distribution and receive calldata in one response. Returns DistributeResult with { distribution, calldata }. Recommended for programmatic SDK usage.

Two-step flow

Create a DRAFT with createDraft(), review and edit recipients with replaceRecipients(), then call prepare() to transition to PREPARED. Use this when you need human review before execution.

Distribution status

DRAFT — created, editable. PREPARED — calldata generated, ready for on-chain execution. IN_PROGRESS — transactions submitted. COMPLETED — all batches confirmed. PARTIALLY_COMPLETED — some failed, some confirmed. FAILED — all batches failed. CANCELLED — manually cancelled.

Transaction batch

Large distributions are split into multiple on-chain transactions (batches). Each batch has its own status (PENDINGSUBMITTEDCONFIRMED or FAILED), transaction hash, and recipient count. Monitor batches with getStats() and getTransactions().

Calldata

Pre-built transaction objects returned by distribute(). Each contains to (contract address), data (encoded function call), value (native token amount), and gasLimit. You sign and submit these — Multisender does not send them for you.

Token approval

ERC-20 tokens require an on-chain approve() transaction before distributing. Use getApproveCalldata() to generate the approval transaction. Native tokens (ETH, POL, etc.) do not require approval — pass 0x0000000000000000000000000000000000000000 as tokenAddress to target the native currency.

Idempotency key

A unique string you provide to prevent duplicate distributions when retrying. If you send the same idempotencyKey twice, the second request returns the existing distribution instead of creating a new one.

Quick Start

Common Workflows

Single-step distribution (recommended)

Create a distribution and get calldata in one call. Best for programmatic SDK usage when you want to send tokens immediately.

1

2

distribute()

Create the distribution and receive `{ distribution, calldata }` — the calldata contains transactions to sign

3

Sign & submit transactions

Sign and submit each transaction from `calldata.transactions` using your wallet (ethers.js, viem, web3.js)

4

getStats()

Poll for batch completion — when `confirmed + failed === total`, the distribution is done

Two-step distribution (with review)

Create a draft, review recipients, then prepare and execute. Best when you need human review before committing.

1

createDraft()

Create a distribution in DRAFT status with recipients or a list ID

2

updateDraft() / replaceRecipients()

Optionally update metadata or replace recipients while in DRAFT

3

getApproveCalldataForDistribution()

Generate approval for the exact amount needed by this distribution (ERC-20 only)

4

prepare()

Generate calldata — transitions from DRAFT to PREPARED

5

getTransactions()

Retrieve the generated transaction batches with calldata for signing

Methods

sdk.distributions.list(params?)

Retrieve all distributions for your project with pagination. Use this to browse distribution history, monitor active distributions, or find a specific distribution by name. Results are sorted by creation date by default.

Parameters

NameTypeRequiredDescription

params.page

number

No

Page number (default: 1)

params.limit

number

No

Items per page (default: 10)

params.search

string

No

Filter distributions by name

params.orderBy

string

No

Field to sort by (e.g. createdAt)

params.orderDir

'ASC' | 'DESC'

No

Sort direction

ASC
DESC

Returns

PaginatedResponse<Distribution>

Paginated list of distribution objects

Errors

401

The request is not authorized

403

You do not have permission to access this resource

See Also

distribute()

Create a new distribution

sdk.distributions.get(id)

Retrieve a single distribution by ID. Returns full details including current status, chain/token info, recipient and amount totals, and timestamps. Use this to check the state of a distribution or to poll for status changes after execution.

Parameters

NameTypeRequiredDescription

id

string

Yes

Distribution ID

Returns

Distribution

Full distribution object

Errors

400

Invalid distribution id

401

The request is not authorized

403

You do not have permission to access this resource

404

Distribution not found

Notes

Status lifecycle: DRAFTPREPAREDIN_PROGRESSCOMPLETED / FAILED / CANCELLED

executedAt is set when execution starts; completedAt is set when all batches finish

See Also

getStats()

Get batch-level completion counts for progress tracking

getTransactions()

View individual transaction batches and their on-chain hashes

cancel()

Cancel this distribution if not yet completed

sdk.distributions.getStats(id)

Get aggregate transaction batch statistics for a distribution. Returns counts of batches by status — use this to build progress bars or determine when a distribution is complete. A distribution is finished when confirmed + failed === total.

Poll getStats() periodically to show a progress bar. The distribution is done when confirmed + failed === total. Check failed > 0 to detect partial failures.

Parameters

NameTypeRequiredDescription

id

string

Yes

Distribution ID

Returns

DistributionStats

Batch status counts

Errors

400

Invalid distribution id

401

The request is not authorized

403

You do not have permission to access this resource

404

Distribution not found

See Also

get()

Get the overall distribution status and details

getTransactions()

Inspect individual batches — get txHash for block explorer verification

sdk.distributions.getTransactions(id, params?)

Retrieve individual transaction batches for a distribution with pagination. Each batch represents a group of recipients processed in a single on-chain transaction. Use this to get transaction hashes for block explorer verification or to debug failed batches.

Parameters

NameTypeRequiredDescription

id

string

Yes

Distribution ID

params.page

number

No

Page number (default: 1)

params.limit

number

No

Items per page (default: 10)

params.orderBy

string

No

Field to sort by

params.orderDir

'ASC' | 'DESC'

No

Sort direction

ASC
DESC

Returns

PaginatedResponse<DistributionTransaction>

Paginated list of transaction batches

Errors

400

Invalid distribution id

401

The request is not authorized

403

You do not have permission to access this resource

404

Distribution not found

Notes

Transaction batch statuses: PENDINGSUBMITTEDCONFIRMED (or FAILED)

txHash is available after submission — use it to verify on a block explorer

Each batch covers a subset of recipients; recipientCount shows how many

See Also

getStats()

Get aggregate counts instead of individual batches

get()

Get the overall distribution status

sdk.distributions.getApproveCalldata(request)

Generate ERC-20 token approval calldata. Returns a transaction that calls approve(spender, amount) on the token contract, allowing the Multisender contract to spend your tokens. Sign and submit this transaction before distributing ERC-20 tokens. Skip this method entirely for native currency (ETH, POL, BNB, etc.) — native tokens do not require approval. Calling it with the zero address produces an invalid approval.

Skip for native currency

This method is only needed for ERC-20 token distributions. If you are distributing native currency (ETH, POL, BNB, etc.) — i.e. using tokenAddress: 0x0000000000000000000000000000000000000000 in distribute() / createDraft() — skip this step entirely. No approval is required for native tokens.

Parameters

NameTypeRequiredDescription

request.chainId

number

Yes

Blockchain chain ID (determines which Multisender contract is the spender)

request.tokenAddress

string

Yes

ERC-20 token contract address to approve. Do NOT pass the zero address here — native currency (ETH, POL, BNB, etc.) does not require approval, skip this method entirely.

request.amount

string

Yes

Amount in wei (integer string, no decimals) or "max" for unlimited approval (uses maxUint256)

Returns

ApproveCalldata

Pre-built approval transaction — sign and submit to your wallet

Errors

400

Validation error

401

The request is not authorized

403

You do not have permission to access this resource

Notes

Only needed for ERC-20 tokens. Native currency (ETH, POL, BNB, etc.) does not require approval — skip this method entirely

Do not call this method with the zero address 0x0000000000000000000000000000000000000000 — it represents native currency, for which no approval exists

amount: "max" sets unlimited approval — convenient for repeated distributions

The spender in the response is the Multisender contract address for the specified chain

See Also

distribute()

Next step — create distribution after approval

getApproveCalldataForDistribution()

Auto-calculate exact approval amount from an existing distribution

getChain()

Find the Multisender contract address for a chain

sdk.distributions.getApproveCalldataForDistribution(id)

Generate ERC-20 approval calldata for a specific distribution. Automatically calculates the exact approval amount based on the distribution's totalAmount — no need to compute it yourself. Use this in the two-step flow after creating a draft.

Parameters

NameTypeRequiredDescription

id

string

Yes

Distribution ID (must have a non-zero totalAmount)

Returns

ApproveCalldata

Pre-built approval transaction with exact amount from the distribution

Errors

400

Invalid distribution id

401

The request is not authorized

403

You do not have permission to access this resource

404

Distribution not found

Notes

The distribution must have recipients (non-zero totalAmount) for this to work

Returns the same ApproveCalldata format as getApproveCalldata() but calculates amount automatically

Skip this method if the distribution targets native currency (tokenAddress = 0x0000000000000000000000000000000000000000) — native transfers do not require approval

See Also

getApproveCalldata()

Manual approval with custom amount (for single-step flow)

prepare()

Next step — prepare calldata after token approval

createDraft()

Create the draft distribution first

sdk.distributions.distribute(request)

Create a distribution and return both the distribution object and transaction calldata in a single call. Accepts inline recipients (csv or recipients tuples) — does not support listId. To distribute from an existing list, use createDraft({ listId })prepare(). This is the primary method for SDK integrations — you get everything needed to sign and submit transactions immediately.

Sending native currency (ETH, POL, BNB, …)

Pass the zero address 0x0000000000000000000000000000000000000000 as tokenAddress to distribute native currency. No approve() step is required, and the generated calldata already includes the required value on each transaction. The server normalizes tokenSymbol to the chain’s nativeSymbol.

Calldata summary

The calldata.summary field provides aggregate info: totalRecipients, totalAmount, estimatedGas, and estimatedCost. Use this to show the user a confirmation before signing.

Need to use an existing list?

distribute() only accepts inline recipients (csv or recipients tuples). To distribute from an existing recipient list, use the two-step flow: createDraft({ listId })prepare().

Use createDraft() with listId

Parameters

NameTypeRequiredDescription

request.chainId

number

Yes

Target blockchain chain ID (1=Ethereum, 137=Polygon, 8453=Base, 42161=Arbitrum, 10=Optimism)

request.tokenAddress

string

Yes

ERC-20 token contract address to distribute. For native currency (ETH, POL, BNB, etc.) pass the zero address 0x0000000000000000000000000000000000000000.

request.tokenSymbol

string

Yes

Token symbol (e.g. "USDC", "WETH"). For native currency the server normalizes this to the chain’s nativeSymbol — you can pass any placeholder.

request.recipients

string[][]

No

Array of [address, amount] tuples — mutually exclusive with csv

request.csv

string

No

CSV string with address,amount per line — mutually exclusive with recipients

request.account

string

Yes

Sender wallet address — required, calldata is generated for this sender

request.idempotencyKey

string

No

Unique key to prevent duplicate distributions on retry

Returns

DistributeResult

{ distribution, calldata } — distribution object + transactions to sign and submit

Errors

400

Validation error

401

The request is not authorized

403

You do not have permission to access this resource

Notes

This is the recommended method for SDK integrations — returns everything in one call

The calldata.summary provides totals across all transactions for display purposes

Provide either recipients or csv, not both — listId is not supported

Use idempotencyKey to safely retry failed requests without creating duplicates

ERC-20 tokens require a prior approve() to the Multisender contract

See Also

getApproveCalldata()

Generate ERC-20 approval before distributing (required step for ERC-20)

getStats()

Monitor batch completion after submitting transactions

createDraft()

Use an existing recipient list via listId (not supported in distribute)

sdk.distributions.createDraft(request)

Create a distribution in DRAFT status. This is the first step of the two-step flow — create a draft, optionally review and edit recipients, then call prepare() to generate calldata. You can provide recipients directly, reference an existing list by listId, or add recipients later with replaceRecipients().

Sending native currency (ETH, POL, BNB, …)

Pass the zero address 0x0000000000000000000000000000000000000000 as tokenAddress to target the native currency. No token approval is needed for the later prepare() step. The server normalizes tokenSymbol to the chain’s nativeSymbol.

You can create a draft without recipients and add them later using replaceRecipients(). This is useful when the recipient list needs to be built incrementally.

Add recipients later

Parameters

NameTypeRequiredDescription

request.name

string

Yes

Distribution name

request.chainId

number

Yes

Target blockchain chain ID

request.tokenAddress

string

Yes

ERC-20 token contract address. For native currency (ETH, POL, BNB, etc.) pass the zero address 0x0000000000000000000000000000000000000000.

request.tokenSymbol

string

Yes

Token symbol (e.g. "USDC"). For native currency the server normalizes this to the chain’s nativeSymbol.

request.notes

string

No

Optional notes or description

request.listId

string

No

Use recipients from an existing list — mutually exclusive with recipients

request.recipients

RecipientDto[]

No

Inline recipients [{ address, amount, label?, tags? }] — mutually exclusive with listId

request.account

string

No

Sender wallet address

request.idempotencyKey

string

No

Unique key to prevent duplicates — returns existing distribution if key already used

request.isDeflationary

boolean

No

Set to true if the token has transfer fees (deflationary tokens)

request.strategy

string

No

Distribution execution strategy

Returns

Distribution

Created distribution in DRAFT status — editable until you call prepare()

Errors

400

Validation error

401

The request is not authorized

403

You do not have permission to access this resource

Notes

Provide listId or recipients, not both — they are mutually exclusive

If listId is used, the list must exist in your project and all items must have amounts

The distribution stays in DRAFT until you call prepare()

Use idempotencyKey to prevent duplicate drafts on retry

See Also

updateDraft()

Update draft metadata (name, chain, token) before preparing

replaceRecipients()

Replace or set recipients on the draft

prepare()

Generate calldata when ready — transitions to PREPARED

getApproveCalldataForDistribution()

Get exact token approval amount for this distribution

sdk.distributions.updateDraft(id, request)

Update metadata of a distribution in DRAFT status. Change the name, chain, token, or sender address. Only works while the distribution is in DRAFT — once prepared, metadata cannot be changed. To change recipients, use replaceRecipients() instead.

Only distributions in DRAFT status can be updated. Once you call prepare(), the distribution transitions to PREPARED and can no longer be edited.

Switching to native currency

Pass tokenAddress: 0x0000000000000000000000000000000000000000 to switch the draft to native currency (ETH, POL, BNB, …). No approval step is required on the subsequent prepare(). The server normalizes tokenSymbol to the chain’s nativeSymbol.

Parameters

NameTypeRequiredDescription

id

string

Yes

Distribution ID (must be in DRAFT status)

request.name

string

No

Updated distribution name

request.notes

string

No

Updated notes

request.chainId

number

No

Updated chain ID

request.tokenAddress

string

No

Updated token address. Pass 0x0000000000000000000000000000000000000000 to target the native currency.

request.tokenSymbol

string

No

Updated token symbol

request.account

string

No

Updated sender wallet address

request.isDeflationary

boolean

No

Whether the token is deflationary

request.strategy

string

No

Distribution execution strategy

Returns

Distribution

Updated distribution object (still in DRAFT status)

Errors

400

Invalid distribution id

401

The request is not authorized

403

You do not have permission to access this resource

404

Distribution not found

409

Not in DRAFT status

Notes

Only works in DRAFT status — returns an error for any other status

Cannot update recipients through this method — use replaceRecipients() for that

Only include fields you want to change — omitted fields remain unchanged

See Also

createDraft()

Create the draft first

replaceRecipients()

Update recipients (cannot be done through updateDraft)

prepare()

Prepare calldata when editing is complete

sdk.distributions.replaceRecipients(id, request)

Replace all recipients on a DRAFT distribution. This is a full replacement — all existing recipients are removed and replaced with the new list. Use this to update the recipient list after creating a draft, or to correct recipients before preparing.

This is a full replacement, not an append. All existing recipients are removed and replaced with the new array.

Parameters

NameTypeRequiredDescription

id

string

Yes

Distribution ID (must be in DRAFT status)

request.recipients

RecipientDto[]

Yes

New recipients array [{ address, amount, label?, tags? }] — replaces all existing

Returns

Distribution

Updated distribution with new recipient count and total amount

Errors

400

Invalid distribution id

401

The request is not authorized

403

You do not have permission to access this resource

404

Distribution not found

409

Not in DRAFT status

Notes

Full replacement — all previous recipients are deleted

Only works in DRAFT status

Each recipient requires address and amount; label and tags are optional

See Also

createDraft()

Create the draft distribution first

prepare()

Prepare calldata after finalizing recipients

sdk.distributions.prepare(id, request?)

Generate transaction calldata for a DRAFT distribution. Transitions the status from DRAFT to PREPARED and returns the updated distribution together with the ready-to-sign transaction batches.

For single-step usage, prefer distribute() — it creates, prepares, and returns calldata all in one call.

Use distribute() instead

Parameters

NameTypeRequiredDescription

id

string

Yes

Distribution ID (must be in DRAFT status)

request.account

string

No

Wallet address that will execute transactions

request.rpcUrl

string

No

Custom RPC URL for gas estimation

Returns

DistributeResult

{ distribution, calldata } — the prepared distribution plus the transactions to sign.

Errors

400

Invalid distribution id

401

The request is not authorized

403

You do not have permission to access this resource

404

Distribution not found

409

Not in DRAFT status

Notes

Transitions status from DRAFTPREPARED

The distribution must have recipients (either from createDraft() or replaceRecipients())

Can be re-run on a DRAFT to regenerate transactions (clears previous ones)

Returns { distribution, calldata } — the same shape as distribute(). Use getTransactions() only to fetch persisted batches later.

For native-currency drafts (tokenAddress = 0x0000000000000000000000000000000000000000) no prior approve() is required — the generated calldata already carries the required value on each transaction

See Also

getApproveCalldataForDistribution()

Get token approval before preparing (ERC-20 only)

getTransactions()

Retrieve generated transaction batches after preparing

distribute()

Alternative: create + prepare + get calldata in one call

sdk.distributions.cancel(id)

Cancel a distribution. Works from DRAFT, PREPARED, or IN_PROGRESS status. Distributions in COMPLETED, PARTIALLY_COMPLETED, or FAILED status cannot be cancelled. Note that cancelling an IN_PROGRESS distribution does not reverse already-confirmed on-chain transactions.

Cancelling an IN_PROGRESS distribution stops further batch submissions but does not reverse transactions already confirmed on-chain. Check getTransactions() to see which batches were already confirmed.

Check confirmed transactions

Parameters

NameTypeRequiredDescription

id

string

Yes

Distribution ID to cancel

Returns

Distribution

Distribution with status updated to CANCELLED

Errors

400

Invalid distribution id

401

The request is not authorized

403

You do not have permission to access this resource

404

Distribution not found

409

Cannot cancel completed distribution

Notes

Can cancel from DRAFT, PREPARED, or IN_PROGRESS status

Cannot cancel COMPLETED, PARTIALLY_COMPLETED, or FAILED distributions

Cancelling IN_PROGRESS does not reverse already-confirmed on-chain transactions

See Also

get()

Check distribution status before cancelling

distribute()

Create a new distribution to replace the cancelled one

Generated Code