> ## 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.

# Money movement

> Take payins and book payouts for a linked client, and what the developer key cannot sign.

A linked client's money is held on its Base smart wallet, and the holder signs each payout from it. Book a payout with `POST /dapi/v1/payouts` and the client's id in `X-Hevn-Account`, then open a `sign` session for the holder.

Send the client's `cl_…` id in `X-Hevn-Account` on the routes below ([Acting as a client](https://docs.gethevn.com/developers/authentication.md#acting-as-a-client)).

## What differs

| Operation | For a linked client | Common page |
| - | - | - |
| Virtual account | `POST /dapi/v1/banks`. The rail delivers the settlement token to the client's wallet. | [Virtual accounts](https://docs.gethevn.com/developers/virtual-accounts.md) |
| Quoted payin | `POST /dapi/v1/payins`. It settles on the client's wallet. | [Payins](https://docs.gethevn.com/developers/payins.md) |
| Transfer on Base | USDC or EURC sent to `baseSmartWallet` is in the balance once it confirms. | [Payins](https://docs.gethevn.com/developers/payins.md) |
| Payout from `USDC` or `EURC` | `POST /dapi/v1/payouts` returns `authorization: "client"` and no `approval`. The holder approves it. | [Payouts](https://docs.gethevn.com/developers/payouts.md) |
| Balance and ledger | `GET /dapi/v1/client/balance` and `GET /dapi/v1/transactions` read the client's wallet. | [Balances and transactions](https://docs.gethevn.com/developers/balances-and-transactions.md) |
| Swap | `POST /dapi/v1/swaps/preview` prices one. `POST /dapi/v1/swaps` is [refused](#refusals). | [Swaps](https://docs.gethevn.com/developers/swaps.md) |
| Escrow, sub account | [Refused](#refusals). | n/a |

Verification comes first for bank rails. A virtual account lists `kyb_required` or `verification_required` in `blockers[]` until the client is verified ([Integration steps](https://docs.gethevn.com/connect/overview.md#integration-steps)).

## Book the payout

Save a contact with `POST /dapi/v1/contacts` ([Payouts](https://docs.gethevn.com/developers/payouts.md)), then call `POST /dapi/v1/payouts` with the contact and one amount. Do not send `publicKey`.

```bash cURL theme={null}
curl -s -X POST "$HEVN_API/payouts" \
  -H "Authorization: Bearer $HEVN_ACCESS_TOKEN" \
  -H "X-Hevn-Account: $HEVN_CLIENT_ID" \
  -H "Idempotency-Key: order-A-1187" \
  -H "Content-Type: application/json" \
  -d '{"contactId":"ct_3K9…","amount":"500.00","paymentReference":"INV-2026-114"}'
```

```python Python theme={null}
payout = client.post("/payouts", {
    "contactId": contact["id"],
    "amount": "500.00",
    "paymentReference": "INV-2026-114",
}, idempotency_key="order-A-1187")
```

```javascript Node theme={null}
const payout = await client.post("/payouts", {
  contactId: contact.id,
  amount: "500.00",
  paymentReference: "INV-2026-114",
}, { idempotencyKey: "order-A-1187" });
```

```go Go theme={null}
payout, err := client.Post("/payouts", hevn.Body{
	"contactId":        contact.Str("id"),
	"amount":           "500.00",
	"paymentReference": "INV-2026-114",
}, hevn.IdempotencyKey("order-A-1187"))
```

```json Response 201, Location: /dapi/v1/payouts/po_4c8a… theme={null}
{
  "id": "po_4c8a…",
  "kind": "fiat",
  "status": "awaitingSignature",
  "quote": { "fromAmount": "500.00", "fromCurrency": "USD", "sourceAccount": "USDC",
             "toAmount": "459.31", "toCurrency": "EUR", …,
             "expiresAt": "2026-09-17T10:06:11Z" },
  "authorization": "client",
  "contact": { "contactId": "ct_3K9…", "name": "Ardenne Fabrication SARL" }
}
```

Show the holder `quote` and `contact` in your product before you open the window. Fields are on [Create an outgoing transfer](https://docs.gethevn.com/api-reference/transfers/create-an-outgoing-transfer.md).

> [!WARNING]
>
> Reuse the `Idempotency-Key` when you retry. A new key books a second payout ([Idempotency-Key](https://docs.gethevn.com/developers/conventions.md#idempotency-key)).

## Approve the payout

Call `POST /dapi/v1/connect/sessions` with `action: "sign"` and the payout id, without `X-Hevn-Account`. Open the returned `url` in the popup ([Approve a payout](https://docs.gethevn.com/connect/sign-in-with-hevn.md#approve-a-payout)).

```bash cURL theme={null}
curl -s -X POST "$HEVN_API/connect/sessions" \
  -H "Authorization: Bearer $HEVN_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"action":"sign","payoutId":"po_4c8a…","redirectUri":"https://app.example.com/hevn/callback"}'
```

```python Python theme={null}
session = hevn.post("/connect/sessions", {
    "action": "sign",
    "payoutId": payout["id"],
    "redirectUri": "https://app.example.com/hevn/callback",
})
```

```javascript Node theme={null}
const session = await hevn.post("/connect/sessions", {
  action: "sign",
  payoutId: payout.id,
  redirectUri: "https://app.example.com/hevn/callback",
});
```

```go Go theme={null}
session, err := api.Post("/connect/sessions", hevn.Body{
	"action":      "sign",
	"payoutId":    payout.Str("id"),
	"redirectUri": "https://app.example.com/hevn/callback",
})
```

```json Response 201 theme={null}
{ "url": "https://sandbox.gethevn.com/connect?session=eyJ…", "state": "pQ8v2Zr0…", "expiresAt": "2026-09-17T10:14:11Z" }
```

The session lasts 10 minutes. Field rules are on [Create a sign-in window session](https://docs.gethevn.com/api-reference/accounts/create-a-sign-in-window-session.md).

| Case | Behaviour | Next |
| - | - | - |
| The holder approves | The callback receives `status=submitted` and `payout=po_…`. | Poll the payout. |
| The holder declines or closes the window | The payout stays `awaitingSignature`. | Create a new `sign` session for the same `po_…`. |
| The quote expired | A routed payout's quote expires at `quote.expiresAt`, and the window then returns `unsupported`. | Open the window right after booking. |
| The holder uses another account | The window returns `not_found`. | Ask the holder to sign in to the linked account. |
| You repeat the booking with the same key | The route returns the same `po_…` with `authorization: "client"`. | Create a new `sign` session. |
| The payout is no longer waiting | `409 payout_not_awaiting_signature` on the session. | Read the payout. |

## Track the payout

Do not act on the redirect. Poll `GET /dapi/v1/payouts/{payoutId}` with the client in `X-Hevn-Account` until `status` leaves `awaitingSignature` and `submitted`.

The window returns `submitted` once the holder's wallet has sent the debit, before the on-chain receipt. The statuses and `failure.code` are in [Payouts](https://docs.gethevn.com/developers/payouts.md), and the polling interval in [Status codes](https://docs.gethevn.com/developers/conventions.md#status-codes).

## Refusals

Your developer key signs for your integrator account and its sub accounts. These calls, made with a linked client in `X-Hevn-Account` or named in the body, are refused.

| Call | Refusal | Instead |
| - | - | - |
| `POST /dapi/v1/payouts/{payoutId}/confirm` | `403 account_not_controlled` | A `sign` session. |
| `POST /dapi/v1/payouts` with `sourceAccount: "FDIC_USD"` | `409 payout_not_fundable`, `details.reason` is `holder_signature_unsupported` | Pay from `USDC` or `EURC`. |
| `POST /dapi/v1/swaps`, `POST /dapi/v1/swaps/{swapId}/confirm` | `403 account_not_controlled` | n/a. The window does not approve swaps. |
| `POST /dapi/v1/escrow` with the client as the buyer | `403 account_not_controlled` | n/a. The window does not approve escrow deals. |
| `POST /dapi/v1/client/accounts` with `kind: "sub"` | `403 account_not_controlled` | [Sub accounts](https://docs.gethevn.com/sub-accounts/overview.md) are opened on your integrator account. |

`account_not_controlled` returns the client's id in `details.clientId`. The other payout refusals are in [Errors](https://docs.gethevn.com/developers/reference/errors.md).

## Sandbox

| Area | Sandbox behaviour |
| - | - |
| Sign-in | A real sign-in. Each test client needs a Google account or email address with no HEVN sandbox account. |
| Allowed sites | Add `http://localhost:<port>` in the sandbox app. |
| Funding | `POST /dapi/v1/sandbox/deposits` with the client in `X-Hevn-Account` ([Mint money](https://docs.gethevn.com/developers/sandbox.md#mint-money)). |
| Verification | `POST /dapi/v1/sandbox/kyb/status` approves a business application or verifies an individual ([Decide a KYB application](https://docs.gethevn.com/developers/sandbox.md#decide-a-kyb-application)). |
| Approval | The holder approves in the window as in production. No sandbox route signs for the holder. |
| Amounts | A payout is capped ([Limits](https://docs.gethevn.com/developers/sandbox.md#limits)). |

> [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.