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

# External accounts

> Register, read and archive the wallet addresses a client holds.

An external account is a wallet address a client holds and signs for, recorded as an `acc_…` id with `kind: "external"`. Register one with `POST /dapi/v1/client/accounts`.

The routes here require `X-Hevn-Account` with the client's id ([Acting as a client](https://docs.gethevn.com/developers/authentication.md#acting-as-a-client)). The same routes return [sub accounts](https://docs.gethevn.com/sub-accounts/overview.md) of your own account, told apart by `kind`.

## Register an address

Call `POST /dapi/v1/client/accounts` with the network and the address. Fields are on [Add an account](https://docs.gethevn.com/api-reference/client-accounts/add-an-account.md).

```bash cURL theme={null}
curl -s -X POST "$HEVN_API/client/accounts" \
  -H "Authorization: Bearer $HEVN_ACCESS_TOKEN" \
  -H "X-Hevn-Account: $HEVN_CLIENT_ID" \
  -H "Content-Type: application/json" \
  -d '{"chain":"base","address":"0x8ba1f109551bD432803012645Ac136ddd64DBA72","label":"Treasury wallet"}'
```

```python Python theme={null}
client = hevn.acting_as(CLIENT_ID)

account = client.post("/client/accounts", {
    "chain": "base",
    "address": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
    "label": "Treasury wallet",
})
```

```javascript Node theme={null}
const client = hevn.actingAs(clientId);

const account = await client.post("/client/accounts", {
  chain: "base",
  address: "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
  label: "Treasury wallet",
});
```

```go Go theme={null}
client := api.ActingAs(clientID)

account, err := client.Post("/client/accounts", hevn.Body{
	"chain":   "base",
	"address": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
	"label":   "Treasury wallet",
})
```

```json Response 201, Location: /dapi/v1/client/accounts/acc_9f2c… theme={null}
{
  "accountId": "acc_9f2c1ab84d7e4f1fa3c65b0e7d9a2c41",
  "kind": "external",
  "asset": "USDC",
  "chain": "base",
  "address": "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
  "label": "Treasury wallet",
  "balance": "0.0",
  "syncedAt": "2026-11-12T09:14:02Z",
  "createdAt": "2026-11-12T09:14:02Z"
}
```

Store `accountId`. It names the account in `accountId`, `sourceAccount` and `destinationAccount` on the [money routes](https://docs.gethevn.com/external-wallets/money-movement.md).

## Address rules

| Rule | Detail |
| - | - |
| Network | `chain` is `base`, `arb`, `eth`, `op`, `pol` or `sol`. One account is one address on one network. |
| Format | A `0x` address on the EVM networks, a base58 address on `sol`. At most 64 characters. |
| Label | Optional, at most 64 characters. It cannot be edited. |
| Uniqueness | One active account per client, network and address. |
| Refused addresses | `422 account_address_refused` for an address not valid on `chain`, a HEVN wallet, a sub account, the zero address, a precompile, and a protocol or token contract. |
| Token | The account holds USDC. `asset` is `USDC`. |
| Ownership | No proof is asked. Register an address your customer controls. |

Payouts need an account on `base`. An account on another network receives payins and returns `409 source_account_unsupported` as a payout source.

## Retries

The address and the label identify the request. An `Idempotency-Key` is accepted and is not needed.

| Request | Result |
| - | - |
| Same network, address and label | `200` with `Idempotency-Replayed: true` and the same account. |
| Same network and address, another label | `409 account_address_taken` |
| An address archived earlier | `201` with a new `acc_…` id. |

## Read accounts

Call `GET /dapi/v1/client/accounts` for a page of the client's active accounts, oldest first, or `GET /dapi/v1/client/accounts/{accountId}` for one. Paging follows [Pagination](https://docs.gethevn.com/developers/conventions.md#pagination).

```bash cURL theme={null}
curl -s "$HEVN_API/client/accounts?limit=50" \
  -H "Authorization: Bearer $HEVN_ACCESS_TOKEN" \
  -H "X-Hevn-Account: $HEVN_CLIENT_ID"
```

```python Python theme={null}
page = client.get("/client/accounts", {"limit": 50})
for row in page["items"]:
    print(row["accountId"], row["chain"], row["address"], row["balance"])
```

```javascript Node theme={null}
const page = await client.get("/client/accounts", { limit: 50 });
for (const row of page.items) console.log(row.accountId, row.chain, row.address, row.balance);
```

```go Go theme={null}
page, err := client.Get("/client/accounts", hevn.Query{"limit": "50"})
for _, row := range page.List("items") {
	fmt.Println(row.Str("accountId"), row.Str("chain"), row.Str("address"), row.Str("balance"))
}
```

The fields are on [List accounts](https://docs.gethevn.com/api-reference/client-accounts/list-accounts.md) and [Retrieve one account](https://docs.gethevn.com/api-reference/client-accounts/retrieve-one-account.md).

## Balance

`balance` is the USDC at the address on `chain`. A read refreshes it from the network when the stored value is older than a minute.

When the network does not respond, the route returns the last value read. `syncedAt` is the time of the last successful read, so compare it with the clock before you show the balance as current.

External accounts have no row in `GET /dapi/v1/client/balance`.

## Archive an account

Call `DELETE /dapi/v1/client/accounts/{accountId}`. The route returns the archived account. See [Archive an external account](https://docs.gethevn.com/api-reference/client-accounts/archive-an-external-account.md).

```bash cURL theme={null}
curl -s -X DELETE "$HEVN_API/client/accounts/$HEVN_ACCOUNT_ID" \
  -H "Authorization: Bearer $HEVN_ACCESS_TOKEN" \
  -H "X-Hevn-Account: $HEVN_CLIENT_ID"
```

```python Python theme={null}
archived = client.delete(f"/client/accounts/{account['accountId']}")
```

```javascript Node theme={null}
const archived = await client.delete(`/client/accounts/${account.accountId}`);
```

```go Go theme={null}
archived, err := client.Delete("/client/accounts/" + account.Str("accountId"))
```

| Effect | Detail |
| - | - |
| Reads | The account leaves the list, and its id returns `404 account_not_found`. |
| Virtual accounts | Each virtual account opened on it is closed. |
| Money routes | The id is refused as `accountId`, `sourceAccount` and `destinationAccount`. |
| Ledger | Its rows stay readable with the `accountId` filter on `GET /dapi/v1/transactions`. |
| Same address again | `POST /dapi/v1/client/accounts` creates a new `acc_…` id with no virtual accounts. |

> [!WARNING]
>
> Archiving closes the virtual accounts opened on the account. Take their account details out of use with payers before you archive.

## Errors

| Error | Cause |
| - | - |
| `404 account_not_found` | Unknown or archived `acc_…` id, or an id of another client. |
| `409 account_address_taken` | The client has an active account with this address on this network under another label. |
| `422 account_address_refused` | The address cannot be an external account. See [Address rules](#address-rules). |
| `422 validation_failed` | Unknown `chain`, or a field over its length. |
| `409 account_archive_unsupported` | `DELETE` on a sub account. |
| `409 account_destination_unsupported` | A virtual account or payin that cannot deliver to this account. |
| `409 source_account_unsupported` | A payout this account cannot fund. |
| `422 refund_address_required` | A payin to this account without `refundAddress`. |

The last three are returned by the routes in [Money movement](https://docs.gethevn.com/external-wallets/money-movement.md). The envelope is in [Errors](https://docs.gethevn.com/developers/reference/errors.md).


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