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

# Stablecoin sends

# Stablecoin sends

Send **stablecoins** from a customer-owned account (`pcus_*` → `account_id`) with preview → confirm → poll.

## Prerequisites

1. [Customers quickstart](/customers/quickstart) — vault `approved` / `active`
2. [Accounts](/customers/accounts) — banking `products.deposit_account.status=ready`, resolve `account_id`
3. [Deposit instructions](/customers/deposit-instructions) — fund the rail if you need inbound balance

<Warning>
  **Sandbox:** self-serve deposits may not credit usable balance for outbound sends. Contact Element Pay for a sandbox credit if you need to exercise preview → confirm. **Live:** fund via [deposit instructions](/customers/deposit-instructions) (bank or on-chain) or corridor [quote → accept](/quickstart) where applicable, then send. On-chain credits usually need the correct network and about **\~2.00** major units or more; wait for balance / `account.credited` before sending.
</Warning>

## Auth and environments

```bash theme={null}
export BASE_SANDBOX="$BASE_SANDBOX"
export BASE_LIVE="$BASE_LIVE"
export BASE="$BASE_SANDBOX"
export API_KEY="is_test_…"
```

```http theme={null}
X-API-Key: <API_KEY>
Content-Type: application/json
```

## Gate

Same banking gate as accounts. If send routes run before `ready`, the API returns **409** with message `Deposit account is not ready`. Response `data` includes `deposit_account_status` or, in some cases, `reason: banking_profile_incomplete`.

## Happy path

<Steps>
  <Step title="Confirm account + balance">
    Use [Accounts](/customers/accounts) to list/get a stablecoin `account_id` with available balance
  </Step>

  <Step title="Preview">
    `POST …/accounts/{account_id}/sends/preview` → `preview_token`
  </Step>

  <Step title="Confirm">
    `POST …/accounts/{account_id}/sends` with `preview_token` + `idempotency_key`
  </Step>

  <Step title="Poll">
    `GET …/accounts/{account_id}/sends/{send_id}` until a **terminal** status (`completed` / `failed`, or your mapped equivalents). Prefer webhooks `account.send.completed` / `account.send.failed` when configured.
  </Step>
</Steps>

## 1. Resolve stablecoin account

```bash theme={null}
export CUSTOMER_ID="pcus_…"

curl -sS "$BASE/partner/customers/$CUSTOMER_ID/accounts" \
  -H "X-API-Key: $API_KEY" | jq '.data'

export ACCOUNT_ID="21"   # pick a stablecoin rail with balance
```

Details: [Accounts](/customers/accounts). Funding: [Deposit instructions](/customers/deposit-instructions).

## 2. Preview

Preview and confirm must use the **same** `account_id`. The `preview_token` binds customer + account.

```bash theme={null}
curl -sS -X POST "$BASE/partner/customers/$CUSTOMER_ID/accounts/$ACCOUNT_ID/sends/preview" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to_address": "0x40C2f2e0326bD1f647fbeB8732529e08B4DB309f",
    "amount": "5.00",
    "network": "Base",
    "memo": "optional-stellar-memo"
  }' | jq '.data'
```

Save `preview_token`. For Stellar destinations, include `memo` when the recipient requires it.

### Send headroom

Amount must be **strictly below** the account's displayed available balance. Sending the full balance (for example `1.00` when available is `1.00`) returns **422** with `available`, `amount`, and `currency` in `data` when known.

## 3. Confirm

Confirm is a **live money movement** on production.

```bash theme={null}
curl -sS -X POST "$BASE/partner/customers/$CUSTOMER_ID/accounts/$ACCOUNT_ID/sends" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "preview_token": "<from preview>",
    "idempotency_key": "send-2026-08-23-001"
  }' | jq '.data'

export SEND_ID="<from confirm>"
```

## 4. Poll send

```bash theme={null}
curl -sS "$BASE/partner/customers/$CUSTOMER_ID/accounts/$ACCOUNT_ID/sends/$SEND_ID" \
  -H "X-API-Key: $API_KEY" | jq '.data'
```

Prefer webhooks `account.send.completed` / `account.send.failed` when configured ([Webhooks](/webhooks)). Poll GET until a **terminal** status. If the source was debited but status stays non-terminal (for example long `submitted`) for an extended time, treat that as abnormal: keep polling, do **not** assume the destination credited, and escalate to Element Pay ops rather than retrying a second confirm.

## Errors

| Situation                       | Typical                                           | Action                                               |
| ------------------------------- | ------------------------------------------------- | ---------------------------------------------------- |
| Banking gate not ready          | `409` with message `Deposit account is not ready` | Poll `products.deposit_account` until `status=ready` |
| Amount ≥ available              | `422` insufficient balance                        | Lower amount strictly below available                |
| Preview expired / wrong account | `4xx`                                             | Re-preview on the same `account_id`                  |
| Stuck non-terminal after debit  | Long `submitted` / processing                     | Poll GET; escalate; do not double-confirm            |

## Next

* [Accounts](/customers/accounts) · [Deposit instructions](/customers/deposit-instructions) · [Route cheat sheet](/customers/route-cheat-sheet)
