ThemeFontsMountReady
SEND
DocsPricingFeaturesComparisonsHelpSign inRequest access →

SEND / Docs

Swaps API

The multi-wallet market buy and sell endpoint. SEND has no order book and no resting orders.

← DocsAPI Reference9 min readUpdated August 10, 2026

There Are No Order Types

SEND executes market swaps only. There is no order book, no resting order, and no price trigger anywhere in the platform: no limit orders, no stop-losses, no trailing stops, no time-in-force, and no cancel-order or open-orders endpoint. Nothing holds an instruction until a price is reached.

What exists instead is the swap batch -- one request that queues an immediate buy or sell across several of your wallets at once, executed at whatever the DEX gives inside the slippage tolerance you set. Three routes cover the whole surface.

  • POST /api/v1/swaps -- creates a batch. Responds 201.
  • GET /api/v1/swaps?batchId=<uuid> -- batch status. This read is the authoritative one.
  • GET /api/v1/swaps/history?limit=<n> -- your manual swap ledger, newest first. limit defaults to 100 and is clamped to between 1 and 500.

Creating a Swap Batch

The request body names the project, the direction, the mint, and one allocation per participating wallet.

A success is 201 with { batchId, actions }, where each action is { id, walletId, amountIn, status: "pending", scheduledAt }. That is an acknowledgement that the actions were queued -- not that anything executed, and not a price.
  • projectId -- required, and must be a project you own. There is no swap-by-mint endpoint; the DEX and pool are resolved from that project's state.
  • actionType -- "buy" or "sell".
  • tokenMint -- the base58 mint address.
  • allocations -- an array of { walletId, amountIn }. One entry becomes one on-chain transaction.
  • amountIn -- a raw integer: lamports on a buy, raw token units on a sell. Decimal conversion is the caller's job.
  • slippageBps -- optional, defaults to 300 (3%), and must be between 1 and 5000.
  • dex and poolAddress -- optional routing overrides. Sending poolAddress without dex is rejected.

How Execution Actually Works

The POST only enqueues. Rows are written as pending manual swap actions and a wake signal is published so the swap executor claims them within milliseconds; if that signal cannot be delivered, the executor still picks them up on its five-second poll. There is no synchronous execution path and no endpoint that blocks until a swap lands.

Validation runs before anything is queued, and each failure rejects the entire batch. An empty allocations array, a tokenMint that is not valid base58, a slippageBps outside 1 to 5000, or any amountIn of zero all return 422 VALIDATION_ERROR with a message naming the offending field. A wallet that does not exist and a wallet owned by someone else both return 404 NOT_FOUND with identical wording, so the API never reveals that another account's wallet id is real.

Polling a Batch to Completion

GET /api/v1/swaps?batchId= returns exactly one row per submitted action: the terminal ledger row once the action finishes, otherwise its in-flight row. Both arms come from a single query with an anti-join, so a row can never appear twice and the row count never exceeds the number of actions you submitted.

  • Key rows by actionId, never by id. id is null while an action is in flight -- an explicit null, not a missing key -- and is filled in once the ledger row exists.
  • status is "executing" while in flight, then "success" or "failed". Those last two are the terminal set.
  • amountIn and amountOut are null on an in-flight row, deliberately. A fabricated zero on an unproven swap poisons every P&L figure downstream, so render the absence.
  • txHash appears on an in-flight row as soon as the submission is persisted, roughly half a second to a second after submit.
  • Stop polling only when every returned row is terminal AND you hold as many rows as you submitted actions. Both halves matter: with three actions submitted and one finished, "all returned rows are terminal" is vacuously true and a naive client stops with two swaps still running.

Realtime Versus the Poll

Two WebSocket topics mirror this pipeline, and neither replaces the poll. swapSubmissions carries the signature shortly after submit and is never a terminal state. swapResults carries the outcome. Both are best-effort and at-least-once: frames can duplicate, and a client that reloaded or backgrounded its tab can miss them entirely, which is exactly why the backend re-emits terminal results.

  • Treat GET /api/v1/swaps?batchId= as the source of truth and the frames as an accelerant.
  • Dedupe frames by actionId. A repeated terminal frame is expected behaviour, not a bug.
  • swapResults uses a different status vocabulary from the REST ledger -- "completed" and "failed" on the frame versus "success" and "failed" on the row. Do not compare the two directly.
  • Display amounts on a result frame are computed server-side and are absent when the token decimals could not be resolved. Say the metadata is unavailable rather than printing a number you inferred.

What the In-App Panel Does

The Buy/Sell panel on a project chart is one client of this API, and its defaults are its own rather than the API's. It defaults to 100 bps (1%) of slippage where the API defaults to 300, offers 50, 100 and 300 bps presets, and remembers your choice locally between sessions.

  • One execution creates one action per selected wallet, all sharing a single batchId.
  • Percent-of-balance and Max amounts stay disabled until every selected wallet has a fully-read balance, because a ceiling computed from a partial balance understates what you can actually spend.
  • POST /api/v1/swaps is on the write rate-limit tier: 60 requests per minute per user.
←Previous
Wallets API
→Next
WebSocket Events
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