ThemeFontsMountReady
SEND
DocsPricingFeaturesComparisonsHelpSign inRequest access →

SEND / Docs

Wallets API

Generate, list, group, and retire Solana wallets over HTTP -- and the limits that apply.

← DocsAPI Reference8 min readUpdated August 10, 2026

What This API Manages

SEND generates and custodies Solana keypairs for you. There are exactly two kinds of wallet. A wallet set is a named group, and it is the unit every multi-wallet strategy operates on -- trading, aging, volume. A dev wallet stands alone, outside any set, and acts as the deployer wallet for launch and snipe projects.

Every route lives under /api/v1 and carries an Authorization: Bearer header. Successful responses are wrapped as { success, data, message, timestamp }. Failures return { success: false, errorCode, message, timestamp } plus an optional structured data object. All JSON keys are camelCase, and every decimal value -- balances, USD amounts, token quantities -- is sent as a JSON string, never as a number.

No endpoint returns a private key and no endpoint accepts one. Key material never leaves the server, so there is nothing for you to back up and nothing to restore.

Wallet Set Endpoints

A set is created empty or with an opening batch of wallets, then grown, renamed, and eventually retired.

  • GET /api/v1/wallet-sets -- lists your sets. Passing ?cursor= or ?limit= returns a cursor page (default limit 20); passing ?page=, ?pageSize= or ?search= returns an offset page (default page 1, page size 20); passing no parameters returns the legacy unpaginated shape.
  • POST /api/v1/wallet-sets -- creates a set from { name, chain } plus optional description, walletCount and labelPrefix. Responds 201 with only { id, name }, so re-read the set to see addresses.
  • GET /api/v1/wallet-sets/{id} -- set detail, including its member wallets.
  • PATCH /api/v1/wallet-sets/{id} -- updates name and/or description.
  • DELETE /api/v1/wallet-sets/{id} -- responds 204.
  • POST /api/v1/wallet-sets/bulk-delete -- body { walletSetIds }, responds { deleted }.
  • GET /api/v1/wallet-sets/stats?search= -- { count, totalWallets, totalNativeBalance, totalUsdValue } across the filtered sets.
  • GET /api/v1/wallet-sets/{id}/balance -- { totalNativeBalance, totalUsdValue, walletCount }.
  • GET /api/v1/wallet-sets/{id}/wallets -- the members. The response carries a pagination envelope, but the service returns every member in a single page.

Adding Wallets to a Set

POST /api/v1/wallet-sets/{id}/wallets/batch mints new keypairs inside an existing set. The body is { count } plus optional labelPrefix and isPrimaryFirst, and the response is 201 with { wallets }.

When the aged wallet pool is in service but cannot place your request, the call fails 422 with errorCode AGED_POOL_SHORTFALL and a data object of { requested, available, examined }. Handle that code separately from a generic validation error: available is a fresh measurement of what this specific set could draw right now, so it tells you exactly what size to retry at.
  • count must be between 1 and 200. Anything outside that range is refused 422 with the message "count must be between 1 and 200".
  • There is no ceiling on how many wallets a set may hold in total -- only on how many one request may mint. Build a larger set by calling the endpoint repeatedly.
  • labelPrefix is optional. Omit it and wallets are labelled with the set name plus an index, so a set named "Runners" produces "Runners 1", "Runners 2", and so on.
  • This route sits on the heavy-write rate-limit tier: 5 requests per minute. POST /api/v1/wallets/dev and POST /api/v1/projects/{id}/launch share that tier, and a script that paces itself badly will spend most of its time being throttled.

Individual Wallets and Dev Wallets

Wallet-level routes work across every set you own, and dev wallets have their own pair of create and delete routes because they belong to no set.

  • GET /api/v1/wallets?chain=&walletSetId=&isActive= -- a flat list of your wallets with optional filters.
  • GET /api/v1/wallets/{id} -- a single wallet.
  • PATCH /api/v1/wallets/{id} -- updates label and/or isActive.
  • GET /api/v1/wallets/{id}/balance -- the cached balance snapshot. GET /api/v1/wallets/{id}/balance/live performs a live read instead.
  • GET /api/v1/wallets/dev?chain=&limit=&cursor=&search= -- dev wallets. With ?cursor= you get a cursor page (default limit 50); otherwise a flat list.
  • POST /api/v1/wallets/dev -- creates a standalone dev wallet from { label, chain }, where chain defaults to solana. Responds 201, heavy-write tier.
  • DELETE /api/v1/wallets/dev/{id} -- responds 204.

Reading Balances

A wallet object always carries id, chain, address, nativeBalance, totalUsdValue, isActive, isDevWallet, createdAt and updatedAt. It carries label, walletSetId, derivationIndex, transactionCount and antiDetectionScore when those values are known.

GET /api/v1/wallets/{id}/balance returns { nativeBalance, totalUsdValue, tokens }, where each token entry is { mintAddress, amount, decimals } plus symbol, name and usdValue when they resolve.

  • Optional fields are omitted from the JSON entirely rather than sent as null. An absent field means unknown, which is not the same as zero -- rendering 0 for an unpriced holding reports a balance you never measured.
  • POST /api/v1/wallets/prime-tracking asks the platform to enroll all of your active wallets into balance tracking. It responds 202 with { requested }, which counts the addresses published to the enrollment queue.
  • That 202 is not a confirmation. It does not mean any balance was refreshed, and the number is a request size, not a result -- enrollment is performed later by a background worker.

Deletes, Ownership, and Errors

Every delete on this API is a soft delete. The route answers 204, the record is flagged inactive, and it disappears from default listings while remaining intact behind any historical record that references it.

  • Bulk operations validate the entire list before touching anything. One unknown or foreign id rejects the whole request -- there is no partial delete.
  • A wallet you do not own is reported as 404 NOT_FOUND rather than 403, so the API never confirms that another account's wallet id is real.
  • Validation failures are 422 VALIDATION_ERROR, not 400. A wallet set name is required, trimmed, and limited to 32 characters.
  • The chain field accepts solana and ethereum case-insensitively; anything else is 422. Only Solana is supported end to end -- trading, launches and exchange funding are all Solana-only -- so an Ethereum set is a container and nothing more.
  • Reads are limited to 120 requests per minute per user and writes to 60, with the heavy-write routes above at 5. Exceeding a quota returns 429 with errorCode RATE_LIMITED.
←Previous
API Authentication
→Next
Swaps API
Was this article helpful?

SEND

Execution infrastructure for Solana. Coordinated execution across thousands of wallets, with a footprint that reads as thousands of strangers.

TwitterDiscordGitHub

Product

FeaturesPricingComparisonsChangelogDocumentation

Company

AboutAmbassador ProgramContact

Legal

PrivacyTerms

Support

Help CenterDiscordTwitter

© SEND 2026 — All rights reserved

Powered by ChainKit