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

> ## Agent Instructions
> HEVN is payments software: an API and app over a Base smart wallet. HEVN is not a bank and holds no key to the wallet. Virtual accounts, fiat payins and fiat payouts are provided by partner banks, which hold fiat while it is in transit. Self-serve (the General tab): the person who controls the email signs for the wallet. Developers integrate /dapi/v1 in one of two ways. HEVN Connect (recommended, the HEVN Connect tab): the integrator's customer creates or links a HEVN account in a HEVN-hosted sign-in window on the integrator's site, the integrator's backend reads the linked account and books its payouts, and the account holder approves each payout in that window. External wallets (the External wallets tab, enabled per integrator): the integrator creates a client through the API, registers a wallet address the customer holds as an external account, and requests virtual accounts that deliver to that address. The customer's own wallet sends each transfer that funds a payout. The developer key signs for the integrator's wallet and its sub accounts and cannot sign for a client's wallet.
> Use HEVN's terms as written. A product is the region a client requests. A rail is the bank route HEVN picks for the product. A virtual account (bnk_) is the record a partner bank opens for a client. Account details are what a payer needs to send a bank transfer, returned in a field named requisites. A client (cl_) is a customer's account: linked to the integrator through Sign in with HEVN (POST /dapi/v1/connect/sessions, then POST /dapi/v1/clients/link), or created with POST /dapi/v1/clients for an external-wallets integration. An external account (acc_, kind external) is a wallet address the client holds and signs for. A sub account (acc_, kind sub) is a further wallet of the integrator's own account on Base, spent with the developer key. Write 'sub account' as two words. A contact is a saved destination. A beneficiary is the party that receives a fiat payout. Money leaving an account is a payout, whether it goes to a bank account or to a wallet.
> Do not name a bank, payment institution, card issuer, identity-verification vendor or stablecoin issuer. Say 'the partner bank'. Do not describe HEVN as licensed, regulated or insured.
> HEVN publishes no fee rates, spreads or minimums. Prices come from a quote on a specific payment. Direct pricing questions to HEVN and do not invent numbers.
> The API is at /dapi/v1 and takes a developer-key session plus an X-Hevn-Account header. Developer keys have an IP allowlist and no scopes. Remote transfers are at /api/v1/remote_spend_limit and take a remote transfer key (rsl_) in X-Api-Key, bounded by an onchain spend permission the account holder grants. The two credentials are separate and neither works on the other API. The HEVN CLI is discontinued.

# Swaps

> Move money between two accounts of your integrator account: USDC to EURC, or to and from a sub account.

A swap moves money between two accounts that the same owner holds, for example `USDC` to `EURC`. Create one with `POST /dapi/v1/swaps` and sign it with your developer key.

A swap moves your own money. A session acting for a client can preview a swap but cannot create one, for either integration kind.

`sourceAccount` and `destinationAccount` take an [account key](https://docs.gethevn.com/developers/overview.md#account-keys) or the `acc_…` id of a sub account ([Sub account moves](#sub-account-moves)).

## Preview a swap

`POST /dapi/v1/swaps/preview` returns the best price among the routes that serve the pair. Preview has no side effects.

```bash cURL theme={null}
curl -s -X POST "$HEVN_API/swaps/preview" \
  -H "Authorization: Bearer $HEVN_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sourceAccount":"USDC","destinationAccount":"EURC","amount":"500.00"}'
```

```python Python theme={null}
priced = hevn.post("/swaps/preview", {
    "sourceAccount": "USDC",
    "destinationAccount": "EURC",
    "amount": "500.00",
})
```

```javascript Node theme={null}
const priced = await hevn.post("/swaps/preview", {
  sourceAccount: "USDC",
  destinationAccount: "EURC",
  amount: "500.00",
});
```

```go Go theme={null}
priced, err := api.Post("/swaps/preview", hevn.Body{
	"sourceAccount":      "USDC",
	"destinationAccount": "EURC",
	"amount":             "500.00",
})
```

```json Response: 200 theme={null}
{ "sourceAccount": "USDC",
  "destinationAccount": "EURC",
  "quote": { "fromAmount": "500.00", "fromCurrency": "USDC",
             "toAmount": "462.14", "toCurrency": "EURC",
             "rate": "0.924280", "feeAmount": "0.75", "feeCurrency": "USDC",
             "minimumToAmount": "461.21", "estimated": false,
             "expiresAt": "2026-09-20T18:12:41Z" } }
```

Fields: [Price a transfer between the client's own accounts](https://docs.gethevn.com/api-reference/transfers/price-a-transfer-between-the-clients-own-accounts.md).

## Create and confirm

Call `POST /dapi/v1/swaps` with the preview body plus `publicKey` and an [`Idempotency-Key`](https://docs.gethevn.com/developers/conventions#idempotency-key). It prices the swap again and returns the approval.

```json Response: 201, Location: /dapi/v1/swaps/swp_9f2c1ab84d theme={null}
{ "id": "swp_9f2c1ab84d",
  "status": "awaitingSignature",
  "idempotencyKey": "swap-A-1187",
  "sourceAccount": "USDC",
  "destinationAccount": "EURC",
  "quote": { "fromAmount": "500.00", "fromCurrency": "USDC",
             "toAmount": "462.14", "toCurrency": "EURC",
             "rate": "0.924280", "feeAmount": "0.75", "feeCurrency": "USDC" },
  "authorization": "debit",
  "approval": { "id": "b1e7…", "payload": "eyJib2R5Ijp7…", "expiresAt": "2026-09-20T18:10:59Z" },
  "debit": { "address": "0x8c41…", "sourceAddress": "0x2f1c…",
             "amount": "500.00", "amountAtomic": "500000000",
             "token": "USDC", "chainId": 8453, "operation": { … } } }
```

When `authorization` is `debit`, compare `debit.sourceAddress`, `debit.address`, `debit.amount` and `debit.token` with the swap you meant, and check `debit.operation`, before you sign ([Debit contents](https://docs.gethevn.com/developers/signing.md#debit-contents)). Fields: [Create a transfer between the client's own accounts](https://docs.gethevn.com/api-reference/transfers/create-a-transfer-between-the-clients-own-accounts.md).

Sign `approval.payload` and post it to `POST /dapi/v1/swaps/{swapId}/confirm` ([Signing](https://docs.gethevn.com/developers/signing.md)).

Confirm returns `202` with a `pollUrl`. Read `GET /dapi/v1/swaps/{swapId}` until `status` is `settled` or `failed`. While the approval is open, retry as described in [Retrying a confirm](https://docs.gethevn.com/developers/signing.md#retrying-a-confirm). Once the approval is used or expired, confirm returns `409 swap_not_confirmable`, so read the swap.

## Read a swap

`GET /dapi/v1/swaps/{swapId}` returns the status and the quote the swap was fixed at.

```json Response: 200 theme={null}
{ "id": "swp_9f2c1ab84d",
  "status": "settled",
  "sourceAccount": "USDC",
  "destinationAccount": "EURC",
  "quote": { "fromAmount": "500.00", "fromCurrency": "USDC",
             "toAmount": "462.14", "toCurrency": "EURC",
             "rate": "0.924280", "feeAmount": "0.75", "feeCurrency": "USDC" },
  "transactionHash": "0x7d2b…",
  "transactionId": "txn_5c9e2f…",
  "createdAt": "2026-09-20T18:08:44Z",
  "settledAt": "2026-09-20T18:09:12Z" }
```

A swap that involves an `FDIC_*` account has a `transactionId` once it is on the [ledger](https://docs.gethevn.com/developers/balances-and-transactions.md). Between token accounts `transactionId` is null, so match the swap on `transactionHash`. Fields: [Retrieve a transfer between the client's own accounts](https://docs.gethevn.com/api-reference/transfers/retrieve-a-transfer-between-the-clients-own-accounts.md).

To pay out of `FDIC_USD` without a swap, see [Payouts](https://docs.gethevn.com/developers/payouts.md#bank-held-balance).

## Sub account moves

A move is a swap with the `acc_…` id of a [sub account](https://docs.gethevn.com/sub-accounts/overview.md) as `sourceAccount` or `destinationAccount`. It uses the same routes, the same `swp_…` resource and the same confirm.

```json theme={null}
{ "sourceAccount": "USDC", "destinationAccount": "acc_5Jd8Qw2LmX", "amount": "250.00",
  "publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE…" }
```

| Rule | Detail |
| - | - |
| Pairs | The account key of a token and a sub account that holds it, or two sub accounts of the same token |
| Price | One for one, with no fee. `quote.toAmount` equals `quote.fromAmount`. |
| `authorization` | `debit` of the account the money leaves. `debit.sourceAddress` is that account and `debit.address` is the receiving account's address. |
| Another pair | `409 account_destination_unsupported` into a sub account, `409 source_account_unsupported` out of one |
| External account | `404 account_not_found`. No move exists between a HEVN wallet and an external account. |

The response and `GET /dapi/v1/swaps/{swapId}` return the ids as sent. The exit for a token a sub account does not hold, the `RD` rules and the ledger rows of a move are on [Sub accounts](https://docs.gethevn.com/sub-accounts/money-movement.md).

## Statuses

| `status` | Meaning | Next |
| - | - | - |
| `awaitingSignature` | Created and not yet confirmed. | Sign and confirm. |
| `submitted` | Confirmed and settling. | Read the swap. |
| `settled` | Settlement completed. | n/a |
| `failed` | The swap did not settle. | Read `failure.code`. |

## Refusals

| Error | Cause | Action |
| - | - | - |
| `400 invalid_request` | No route serves the pair. | Choose another pair of accounts. |
| `422 account_unavailable` | The owner does not hold the `FDIC_*` account. | Use an account from the [balance](https://docs.gethevn.com/developers/balances-and-transactions.md#balance). |
| `422 swap_route_unavailable` | The [sandbox](https://docs.gethevn.com/developers/sandbox.md) does not run a swap or preview between two account keys. It serves a move. | n/a |
| `403 account_not_controlled` | `POST /dapi/v1/swaps` or its confirm was called with a client in `X-Hevn-Account`. | Swap your own accounts. A client's accounts cannot be swapped through the API. |
| `409 account_destination_unsupported`, `409 source_account_unsupported` | The pair is not a move a sub account can make. | See [Sub account moves](#sub-account-moves). |
| `404 account_not_found` | The `acc_…` id is unknown or names an external account. | Use a sub account of your own. |
| `409 swap_not_confirmable` | The approval was used or has expired. | Read the swap. |

Other codes: [Errors](https://docs.gethevn.com/developers/reference/errors.md).

> [card] [Next: Balances and transactions](https://docs.gethevn.com/developers/balances-and-transactions.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.