npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@multisender.app/multisender-sdk

v0.1.1

Published

TypeScript SDK for Multisender Enterprise API - mass token distributions across EVM chains

Readme

Multisender SDK

npm version TypeScript License: MIT

TypeScript SDK for the Multisender Enterprise API - streamline mass token distributions across multiple EVM chains.

Features

  • 🚀 Simple API - Intuitive methods for token distributions
  • 📦 Full TypeScript Support - Complete type safety and IntelliSense
  • 🔗 Multi-Chain - Support for Ethereum, Polygon, Arbitrum, Optimism, Base, and more
  • 📊 CSV Support - Import recipients from CSV files
  • 🛠️ CLI Tools - Command-line interface for quick operations
  • Tested - Comprehensive test coverage with Bun test runner
  • 🌐 Dual Builds - ESM and CommonJS support

Installation

npm install @multisender.app/multisender-sdk

Or with yarn:

yarn add @multisender.app/multisender-sdk

Or with Bun:

bun add @multisender.app/multisender-sdk

Quick Start

import { Multisender } from '@multisender.app/multisender-sdk';

// Initialize the SDK
const multisender = new Multisender({
  apiKey: 'your-api-key-here',
});

// Create a token distribution
const result = await multisender.distributions.distribute({
  chainId: 1, // Ethereum mainnet
  tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
  tokenSymbol: 'USDC',
  recipients: [
    ['0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', '100'],
    ['0x1234567890123456789012345678901234567890', '200'],
  ],
});

console.log('Distribution created:', result.distribution.id);

OpenAPI-First Workflow

This SDK is generated from an OpenAPI spec and committed under src/gen.

Environment placeholders

  • OPENAPI_SPEC_URL (required, points to the OpenAPI JSON endpoint)
  • OPENAPI_SPEC_AUTH_HEADER (optional)
  • OPENAPI_SPEC_AUTH_TOKEN (optional)

Commands

# Regenerate SDK client/types from OpenAPI
bun run generate:api

# Verify generated artifacts are committed and up to date
bun run generate:api:check

Release policy

  • Treat spec changes as the source of truth for SDK surface changes.
  • Include spec revision/source in release notes when publishing.
  • Document migration notes for any spec-driven breaking change.

Migration: OpenAPI-aligned generated operations

The generated client under src/gen now follows the OpenAPI operationId format resource_method. In the published generated entrypoint this becomes camelCase exports without a client prefix, for example projectGetProjectInfo, listsCreate, and distributionsPrepareTransactions.

This is a breaking change only for @multisender.app/multisender-sdk/generated. The high-level façade (Multisender and the *Service classes) keeps the same public method names and behavior.

Import the generated surface from @multisender.app/multisender-sdk/generated and use the new resource-based exports.

Removed generated export names:

  • clientApiKeysGetProjectInfo and clientApiKeysGetProjectMembers
  • clientLists*, clientDistributions*, and clientCatalogs*
  • Older short names such as create2, findAll2, and getProjectInfo

Removed from the SDK (no longer in OpenAPI):

  • Project API key CRUD (listApiKeys, createApiKey, updateApiKey, deleteApiKey).
  • Token catalog methods (getTokens, getToken, searchTokens).

Lists: Removing an entry from a list uses list item id and lists.removeListItem (path /recipients/items/{listItemId}), not recipient id on the old route.

Distributions: CreateDistributeRequest is a discriminated union of recipients or csv (exactly one); draft create uses CreateDistributionRequest (listId or recipients, not both per spec).

API Reference

Initialize SDK

const multisender = new Multisender({
  apiKey: string;           // Required: Your API key
  baseUrl?: string;         // Optional: Custom API base URL
  timeout?: number;         // Optional: Request timeout in ms (default: 30000)
  headers?: Record<string, string>; // Optional: Additional headers
});

Distributions

Create Distribution

Provide exactly one of recipients or csv (the API rejects requests with both or neither).

Recipients:

await multisender.distributions.distribute({
  chainId: 1,
  tokenAddress: '0x…',
  tokenSymbol: 'USDC',
  recipients: [
    ['0x…', '100'],
    ['0x…', '200'],
  ],
  // account: '0x…',        // optional sender wallet
  // idempotencyKey: '…',   // optional dedupe key
});

CSV string:

await multisender.distributions.distribute({
  chainId: 1,
  tokenAddress: '0x…',
  tokenSymbol: 'USDC',
  csv: 'address,amount\n0x…,100\n',
  // account: '0x…',
  // idempotencyKey: '…',
});

List Distributions

const distributions = await multisender.distributions.list({
  page?: number;            // Page number (default: 1)
  limit?: number;           // Items per page (default: 20)
  orderBy?: string;         // Field to order by
  orderDir?: 'ASC' | 'DESC'; // Order direction
  search?: string;          // Search term
});

Get Distribution

const distribution = await multisender.distributions.get('dist_123');

Get Distribution Statistics

const stats = await multisender.distributions.getStats('dist_123');
// Returns: totalRecipients, totalAmount, completedTransactions, etc.

Cancel Distribution

await multisender.distributions.cancel('dist_123');

Lists

Create Recipient List

const list = await multisender.lists.create({
  name: 'VIP Customers',
  notes?: 'Optional notes',
});

List All Lists

const lists = await multisender.lists.list({
  page?: number;
  limit?: number;
});

Get List

const list = await multisender.lists.get('list_123');

Update List

const list = await multisender.lists.update('list_123', {
  name?: 'Updated Name',
  notes?: 'Updated notes',
});

Delete List

await multisender.lists.delete('list_123');

Add Recipients

// Add single recipient
await multisender.lists.addRecipient('list_123', {
  address: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  addressType: 'EVM',
  label?: 'Customer A',
  tags?: ['vip', 'early-adopter'],
});

// Add multiple recipients
await multisender.lists.addRecipientsBulk('list_123', {
  items: [
    { address: '0x...', addressType: 'EVM', label: 'Customer A' },
    { address: '0x...', addressType: 'EVM', label: 'Customer B' },
  ],
});

Remove list item

Removes a row from a list by list item id (the id of the list-item resource, not the recipient id on the legacy route):

const { message } = await multisender.lists.removeListItem('list_123', 'list_item_456');

*Detailed() methods are removed; primary SDK methods now return the full detailed payload.

Project

Get Project Info

const project = await multisender.project.getInfo();

Project members

const members = await multisender.project.getMembers();

API key management (list/create/update/delete) is not part of this SDK’s OpenAPI surface anymore; manage keys in the Multisender product or your upstream API as documented there.

Catalogs

// Supported chains and chain metadata
const chains = await multisender.catalogs.getChains();
const chain = await multisender.catalogs.getChain('1');

Token catalog HTTP endpoints are no longer exposed in the generated client; resolve token metadata via your own sources or the Multisender API docs if new endpoints are added to the spec.

CSV Support

Parse CSV

import { parseCsv } from '@multisender.app/multisender-sdk';

const recipients = parseCsv(csvString, {
  hasHeader: true,
  delimiter: ',',
  skipRows: 0,
});

Generate CSV

import { toCsv } from '@multisender.app/multisender-sdk';

const csv = toCsv([
  ['0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', '100'],
  ['0x1234567890123456789012345678901234567890', '200'],
], true); // includeHeader

CSV Format

address,amount
0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6,100
0x1234567890123456789012345678901234567890,200

CLI Usage

The SDK includes a command-line interface for quick operations.

Install Globally

npm install -g @multisender.app/multisender-sdk

Commands

Distribute Tokens

multisender distribute \
  --api-key YOUR_API_KEY \
  --chain 1 \
  --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \
  --symbol USDC \
  --recipients recipients.csv

List Distributions

multisender distributions list --api-key YOUR_API_KEY

Get Distribution Details

multisender distributions get dist_123 --api-key YOUR_API_KEY

Manage Lists

# Create list
multisender lists create --api-key YOUR_API_KEY --name "My List"

# List all
multisender lists list --api-key YOUR_API_KEY

# Get list
multisender lists get list_123 --api-key YOUR_API_KEY

# Delete list
multisender lists delete list_123 --api-key YOUR_API_KEY

Local development

To use the CLI against a local API (e.g. http://localhost:3000), pass --base-url:

multisender lists list --api-key YOUR_API_KEY --base-url http://localhost:3000
multisender distributions list --api-key YOUR_API_KEY --base-url http://localhost:3000

Supported Chains

| Chain | Chain ID | |-------|----------| | Ethereum | 1 | | Optimism | 10 | | Polygon | 137 | | Base | 8453 | | Arbitrum | 42161 |

Error Handling

import { ApiError, NetworkError, ValidationError } from '@multisender.app/multisender-sdk';

try {
  await multisender.distributions.distribute({ /* ... */ });
} catch (error) {
  if (error instanceof ApiError) {
    console.error('API Error:', error.status, error.body);
  } else if (error instanceof NetworkError) {
    console.error('Network Error:', error.message);
  } else if (error instanceof ValidationError) {
    console.error('Validation Error:', error.message);
  }
}

Examples

See the examples directory for complete examples:

Development

Use Bun for package and script management.

bun install
bun run build
bun run test
bun run test:coverage
bun run typecheck
bun run lint

Browser Support

The SDK works in both Node.js (18+) and modern browsers that support native fetch.

Requirements

  • Runtime: Node.js 18+ or Bun 1+ (for development and consumption)
  • TypeScript 5+ (for development)

License

MIT License - see LICENSE file for details.

Links

Support

For support, email [email protected] or open an issue on GitHub.