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

# Offramp

> Quote and execute offramps from the CLI. Whether a send needs an email code depends on your offramp security settings.

The CLI offramp flow is: quote (optional), create (which executes and, when a code is required, prompts for the emailed OTP to confirm), then show. See [Offramp lifecycle](/concepts/offramp-lifecycle) for the full picture.

Whether an offramp needs a code depends on your offramp security settings, which you manage in the dashboard under **Settings → Offramp security**. The CLI honors these settings but can't change them — the dashboard is the only place to do that. When a code is required, the CLI uses a per-transaction email OTP — the same gate the MCP server uses — rather than the dashboard's session re-verification. Sends to your own saved bank can skip the code if you've turned it off or set an amount threshold; sends to a `@username` or a one-off recipient always require it; sandbox never does.

## Quote

Preview the rate and fees before committing:

```bash theme={null}
veil offramp quote --token USDC --amount 100
```

Flags:

| Flag                     | Required | Description                         |
| ------------------------ | -------- | ----------------------------------- |
| `--token`                | Yes      | `USDC` or `USDT`                    |
| `--amount`               | Yes      | Amount to convert                   |
| `--bank-account-id`      | No       | Specific payout account             |
| `--beneficiary-username` | No       | Send to a `@handle` instead         |
| `--wallet-id`            | No       | Check wallet balance before quoting |

Quoting commits to nothing. You can call it repeatedly. When `--wallet-id` is given, the CLI also checks whether the wallet holds enough balance.

## Create (execute + OTP + confirm)

```bash theme={null}
veil offramp create --wallet-id <id> --amount <n> --token USDC
```

This is a two-step interactive command:

<Steps>
  <Step title="Pre-send confirmation">
    The CLI fetches a quote, prints the amount, fee, and destination, and asks you to confirm:

    ```
    About to send 100 USDC from wallet abc123 to your primary bank (fee ~1.00 USD, you receive ~99.00 USD).
    ? Continue? (y/N)
    ```

    Pass `--yes` to skip this prompt. When your settings require a code, the OTP step below still applies; when they don't, the send completes here.
  </Step>

  <Step title="Execute (and receive an OTP if required)">
    After you confirm, the CLI sends the execute request. When a code is required, Veil creates a pending transaction and emails a six-digit code to your account email:

    ```
    Sent a 6-digit code to y***@example.com. The code expires in 10 minutes.
    ```

    When your settings waive the code, there's no prompt — the CLI prints the transaction details right away.
  </Step>

  <Step title="Enter the OTP">
    ```
    ? Enter the 6-digit code:
    ```

    The CLI accepts up to 5 attempts. On success, it prints the transaction ID, amounts, and status.
  </Step>
</Steps>

Flags:

| Flag                     | Required | Description                                             |
| ------------------------ | -------- | ------------------------------------------------------- |
| `--wallet-id`            | Yes      | Wallet to draw from                                     |
| `--amount`               | Yes      | Amount to convert                                       |
| `--token`                | No       | `USDC` (default) or `USDT`                              |
| `--bank-account-id`      | No       | Override the wallet's default bank                      |
| `--beneficiary-username` | No       | Send to a `@handle`                                     |
| `--binding-token`        | No       | Binding token from `veil usernames beneficiary-preview` |
| `--yes`                  | No       | Skip the pre-send confirmation prompt                   |
| `--live`                 | No       | Execute against live mode                               |

`--bank-account-id` and `--beneficiary-username` are mutually exclusive.

## Show

```bash theme={null}
veil offramp show <id>
```

Prints current status, amounts in and out, fee, wire reference (once settled), and timestamps.

## Idempotency and retries

Each `veil offramp create` invocation generates a fresh idempotency key. If the execute request succeeds but the network drops before you enter the OTP, the unconfirmed transaction expires automatically — you can safely run `veil offramp create` again to start a new one.

If an OTP email was sent before the network error, disregard it — that code is tied to the expired transaction.

## Error codes

These are the codes `veil offramp create` surfaces and what each means:

| Code                             | CLI message                                                          | What to do                                                       |
| -------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `OTP_INVALID`                    | `Incorrect code. N attempt(s) remaining.`                            | Re-enter the code                                                |
| `OTP_EXPIRED`                    | `The verification code has expired.`                                 | Run `veil offramp create` again                                  |
| `OTP_ALREADY_USED`               | `The verification code has already been used.`                       | Run `veil offramp create` again                                  |
| `OTP_TOO_MANY_ATTEMPTS`          | `Too many incorrect attempts on this code.`                          | Run `veil offramp create` again                                  |
| `OTP_EMAIL_MISMATCH`             | `Verification code was sent to a different email address.`           | Run `veil offramp create` again                                  |
| `RATE_CHANGED`                   | `The exchange rate changed too much between quote and confirmation.` | Run `veil offramp create` again                                  |
| `CONFIRMATION_EXPIRED`           | `The confirmation window has expired.`                               | Run `veil offramp create` again                                  |
| `USERNAME_BENEFICIARY_NOT_READY` | `The recipient is not ready to receive offramps.`                    | Check recipient status with `veil usernames beneficiary-preview` |

For any code followed by "Run `veil offramp create` again", the failed transaction is closed — starting a new one is always safe.

## See also

* [Offramp lifecycle](/concepts/offramp-lifecycle) — the full quote-to-settle sequence
* [Usernames](/cli/usernames) — using `beneficiary-preview` before a handle-routed offramp
