> ## Documentation Index
> Fetch the complete documentation index at: https://docs.buckspay.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Swaps

> Optional token-swap surface via the facilitator's swap rail - quoteSwap ships end-to-end; swap enforces a minOut floor.

<Warning>
  Swaps is an **optional** feature surface. `quoteSwap` works end-to-end. `swap` enforces
  the `minOut` floor before submit and fails closed (`SWAP_FAILED`) until the full EVM wallet
  submit path is wired through your BFF. The core SDK (connect, pay, batch, sessions) does
  not depend on this surface.
</Warning>

## Enabling swaps

Pass `swapChain` to `buckspayFacilitator`. Without it, `quoteSwap` and `swap` are omitted
from the relayer and both methods throw if called:

```ts theme={null}
import { buckspayFacilitator } from "@buckspay/relayer/buckspay-facilitator";

const relayer = buckspayFacilitator({
  url: "/api/gasless",    // your BFF - the facilitator API key stays server-side
  network: "testnet",
  swapChain: "base-sepolia"
});
```

## `quoteSwap` - ships end-to-end

`quoteSwap` is signer-agnostic and delegates to `/swap/quote`:

```ts theme={null}
const quote = await client.quoteSwap({
  tokenIn: "0xSellTokenAddress",
  tokenOut: "0xBuyTokenAddress",
  amount: "1000000"
});
// quote: SwapQuote
```

## `swap` - enforces the floor, fails closed

`swap` checks `minOut` before any submit. If the live quote falls below `minOut`, it throws
`BuckspayError("SWAP_FAILED")` without signing or submitting anything:

```ts theme={null}
const receipt = await client.swap({
  tokenIn: "0xSellTokenAddress",
  tokenOut: "0xBuyTokenAddress",
  amount: "1000000",
  minOut: "985000"  // floor: reject if the received amount would be below this
});
```

## Full example

```ts theme={null}
// Recipe 14 - SWAP (STRETCH, optional). Gasless token swap via the facilitator's existing
// /swap rail. NOTE: this is the first feature cut if the cycle tightens - the core surface does
// NOT depend on it. The submit leg uses the EVM wallet typed-data signature through your BFF.
import { createBuckspayClient, createRpcSimContext, type SwapQuote } from "@buckspay/core";
import { classicAccount } from "@buckspay/accounts/classic";
import { walletsKit } from "@buckspay/signers/wallets-kit";
import { buckspayFacilitator } from "@buckspay/relayer/buckspay-facilitator";

const client = createBuckspayClient(
  {
    network: "testnet",
    account: classicAccount(),
    signer: walletsKit({ network: "testnet" }),
    // `swapChain` enables quoteSwap/swap; without it the relayer omits them (fails closed).
    relayer: buckspayFacilitator({
      url: "/api/gasless", // your BFF - the facilitator API key stays server-side
      network: "testnet",
      swapChain: "base-sepolia"
    }),
    gas: { mode: "sponsored" }
  },
  createRpcSimContext("https://soroban-testnet.stellar.org")
);

export async function quoteOnly(): Promise<SwapQuote> {
  await client.connect();
  // quoteSwap is signer-agnostic and works end-to-end today.
  return client.quoteSwap({
    tokenIn: "0xSellTokenAddress",
    tokenOut: "0xBuyTokenAddress",
    amount: "1000000"
  });
}

export async function swapWithFloor(): Promise<void> {
  await client.connect();
  // minOut is enforced BEFORE any submit; a below-floor quote throws SWAP_FAILED.
  const receipt = await client.swap({
    tokenIn: "0xSellTokenAddress",
    tokenOut: "0xBuyTokenAddress",
    amount: "1000000",
    minOut: "985000"
  });
  console.log(receipt.transferTx);
}
```

## Next

<CardGroup cols={2}>
  <Card title="Atomic batch" href="/features/atomic-batch">
    Settle multiple transfers all-or-nothing in one transaction.
  </Card>

  <Card title="Onboarding" href="/features/onboarding">
    How a user with zero XLM gets a payment-ready account.
  </Card>
</CardGroup>
