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

# Private Payments with Ephemeral SPL Tokens

> Use Ephemeral SPL Tokens for private deposits, transfers, and withdrawals — private visibility, stealth handles, and queued settlement over the hosted API.

***

### Quick Access

Check out example:

<CardGroup cols={2}>
  <Card title="GitHub" icon="github" href="https://github.com/magicblock-labs/magicblock-engine-examples/tree/main/spl-tokens" iconType="duotone">
    SPL Tokens Anchor Implementation
  </Card>

  <Card title="Live Example App" icon="coins" href="https://one.magicblock.app/" iconType="duotone">
    Try private payments
  </Card>
</CardGroup>

***

## Overview

**Private Payments** are the privacy use case built on top of [SPL tokens on
ER](/pages/ephemeral-spl-token/overview). The same
deposit / transfer / withdraw primitive runs with **private visibility**, so the amount, destination,
and timing of a payment are shielded rather than broadcast publicly.

<Note>
  New to the primitive? Read the [Ephemeral SPL Tokens
  overview](/pages/ephemeral-spl-token/overview) first — this guide
  assumes the eATA / Global Vault / delegation model.
</Note>

The easiest way to build private payments is the hosted **Ephemeral SPL Token API**, which returns
unsigned transactions you sign and submit.

<CardGroup cols={2}>
  <Card title="API reference" icon="server" href="/pages/ephemeral-spl-token/api-reference/introduction" iconType="duotone">
    Endpoints for deposit, transfer, withdraw, balances, stealth pools, and auth.
  </Card>

  <Card title="Reference program" icon="github" href="https://github.com/magicblock-labs/ephemeral-spl-token" iconType="duotone">
    The on-chain Ephemeral SPL Token program.
  </Card>
</CardGroup>

***

## Privacy model

Private payments rely on:

* **Private visibility** — transfers execute inside the Ephemeral Rollup with `visibility: "private"`,
  so the transfer is not broadcast publicly.
* **Stealth handles** — send to a human-readable name (e.g. `alice@magicblock.id`) instead of a raw
  public key. The handle resolves to one or more destination keys via a **stealth pool**, breaking the
  direct sender → recipient link on-chain.
* **Queued settlement** — private transfers can settle through the program's transfer queue rather than
  a direct, immediately-linkable movement.

<Warning>
  Privacy here reduces **linkability**, not total observability. Amounts and timing may still be
  inferable at the network level. Threat-model your assumptions.
</Warning>

***

## Authentication

Private reads and stealth-pool operations require a bearer token. Obtain one with the challenge/login
flow before calling protected endpoints:

<Steps>
  <Step title="Request a challenge">
    `GET /v1/spl/challenge` returns a message for the user to sign.
  </Step>

  <Step title="Log in">
    `POST /v1/spl/login` exchanges the signed challenge for a bearer token.
  </Step>

  <Step title="Call protected endpoints">
    Send `Authorization: Bearer <token>` on `GET /v1/spl/private-balance` and
    `POST /v1/spl/stealth-pool`.
  </Step>
</Steps>

***

## Deposits

Move tokens into the mint's Global Vault and credit the depositor's ephemeral ATA.

* `POST /v1/spl/deposit` — builds the deposit transaction. Set `private: true` to keep the deposited
  balance private.

The response is an unsigned transaction plus a `sendTo` field (`base` or `ephemeral`). Sign it and
submit via [`POST /v1/transaction/send`](/pages/ephemeral-spl-token/api-reference/transaction-send)
or your own RPC.

***

## Private transfers

* `POST /v1/spl/transfer` with `visibility: "private"`.

Two destination modes:

| Destination    | `to` value                   | Requirements                                                        |
| -------------- | ---------------------------- | ------------------------------------------------------------------- |
| Direct         | recipient public key         | `visibility: "private"`                                             |
| Stealth handle | an initialized handle string | `visibility: "private"`, `fromBalance: "base"`, `toBalance: "base"` |

To use a stealth handle, initialize it first:

* `POST /v1/spl/stealth-pool` — map a handle (≤255 UTF-8 bytes; **not** normalized, so
  `Alice@…` ≠ `alice@…`) to 1–10 destination owner keys, optionally splitting payments across them.
* `GET /v1/spl/stealth-pool?handle=…` — check whether a handle's pool exists.

<Note>
  Handles are stored as their exact UTF-8 bytes. `GET` returns only whether the pool exists — never the
  destination keys.
</Note>

***

## Fees and gasless transfers

`visibility` and `gasless` are independent request fields: `visibility` controls how the transfer is
routed, while `gasless` controls who pays gas. The cost of a private transfer is the sum of a
**privacy fee**, which always applies, and the chosen **gas payment mode**.

Every private base → base transfer pays a **0.1% (10 bps) privacy fee**, charged in the token being
transferred — not in SOL. Gas can be paid in either of two modes:

|                     | Self-paid               | Gasless (`gasless: true`)          |
| ------------------- | ----------------------- | ---------------------------------- |
| SOL transaction fee | sender pays (needs SOL) | sponsor pays (sender needs no SOL) |
| Relay fee           | none                    | flat 0.2 USDC/USDT to the sponsor  |
| 0.1% privacy fee    | yes, in tokens          | yes, in tokens                     |
| Minimum amount      | none                    | 0.5 USDC/USDT                      |
| Supported mints     | any                     | mainnet USDC/USDT, devnet USDC     |

With `gasless: true`, the configured sponsor becomes the transaction fee payer and co-signs, and the
API prepends a token-transfer instruction that reimburses the sponsor with a flat **0.2 USDC/USDT
relay fee** from the sender's balance. Because the relay fee is flat, gasless transfers require a
minimum of **0.5 USDC/USDT**; the minimum applies only to the gasless mode, not to private transfers
in general. Amounts below it can still be sent with `visibility: "private"` by omitting `gasless`.

A first private transfer may also include a one-time **\~0.00204 SOL** of rent to set up the ephemeral
token account. All token-denominated fees are reported in the transfer response as `fees.tokens`, and
SOL-denominated costs as `fees.lamports`.

<Note>
  A `gasless: true` request below the minimum, or with an unsupported mint, is rejected with a `400`
  error (`INVALID_GASLESS_TRANSFER_AMOUNT` / `INVALID_GASLESS_TRANSFER_MINT`). The API never changes
  the requested `visibility`: a transfer is only public when the request says so. Clients that handle
  gasless errors by rebuilding the request should preserve `visibility: "private"` if privacy is
  intended.
</Note>

`gasless: true` is ignored when `from` is an off-curve PDA owner (gasless requires a wallet sender);
the transfer still executes with the requested visibility, with the sender as fee payer.

***

## Withdrawals

Move a balance back out of the Global Vault to a standard base-layer SPL token account.

* `POST /v1/spl/withdraw` — builds the withdrawal transaction.

Check balances any time:

* `GET /v1/spl/balance` — public balance.
* `GET /v1/spl/private-balance` — private balance (requires the bearer token).

***

## Developer notes

* **Privacy is a spectrum.** Ephemeral SPL tokens reduce linkability; they do not hide amounts, timing,
  or protect against network-level analysis.
* **Handles aren't normalized.** Casing/whitespace matter — display and store handles consistently.
* **Match the flow.** Stealth-handle transfers require `visibility: "private"`, `fromBalance: "base"`,
  `toBalance: "base"` (these are also the omitted-field defaults).
* **Sign then send.** Builder endpoints return unsigned transactions; submit them with
  `POST /v1/transaction/send` and honor the returned `sendTo`.

***

## Next steps

<CardGroup cols={2}>
  <Card title="Ephemeral SPL Tokens — Overview" icon="book" href="/pages/ephemeral-spl-token/overview" iconType="duotone">
    The primitive behind private payments.
  </Card>

  <Card title="SDK Quickstart" icon="rocket" href="/pages/ephemeral-spl-token/quickstart" iconType="duotone">
    The on-chain/SDK integration path.
  </Card>
</CardGroup>
