# `BankingCircle.VirtualAccounts`
[🔗](https://github.com/iamkanishka/banking_circle/blob/main/lib/banking_circle/virtual_accounts.ex#L1)

Virtual Accounts (VIBANs): externally addressable IBANs that route to
one or more physical Master Accounts rather than holding funds
themselves. Used for account reconciliation (one VIBAN per seller),
treasury consolidation, and third-party account services (POBO/COBO —
paying/collecting on behalf of your customer, under their own name).

## Confidence note

The **list**, **close**, **close-status**, **add-customer-details**, and
**customer-details-status** endpoints below are confirmed against
Banking Circle's docs. The **order/create** endpoint path
(`order/2` in this module) is inferred from consistent "ordering a
virtual account" terminology across the docs and Client Portal, but I
was not able to confirm its exact REST path and payload shape against
the API reference directly — **verify this one against your sandbox or
the API reference before relying on it**, everything else here should
be solid.

## Lifecycle

Order → (optionally) add customer/UBO details for POBO/COBO accounts →
active, usable → close (irreversible, applies to all linked currencies —
no partial closure). Closure has a ~15 minute processing delay and is
paused during a daily window (18:40–20:55 CET); poll
`close_status/3` or watch for `status` flipping from `"Active"` to
`"InActive"` on `list/2`.

UBO information for POBO/COBO accounts can only be set **once** — there
is no update path once submitted, per Banking Circle's docs.

# `client`

```elixir
@type client() :: atom()
```

# `add_customer_details`

```elixir
@spec add_customer_details([map()], client()) ::
  {:ok, map()} | {:error, BankingCircle.Error.t()}
```

Adds customer and Ultimate Beneficial Owner (UBO) details to one or
more POBO/COBO virtual accounts that don't have them yet — required
before such an account can process transactions. This is a **write-once**
operation: it only accepts accounts without existing customer details,
and cannot be used to modify details already set.

`entries` is a list of maps, each requiring `:virtual_account_number`
plus the customer/UBO fields (up to 5 UBOs per account; all string
fields max 35 chars, restricted charset — see Banking Circle's Virtual
Accounts Reference Data for the exact allowed field set).

# `close`

```elixir
@spec close([map()], client()) :: {:ok, map()} | {:error, BankingCircle.Error.t()}
```

Closes one or more virtual accounts. Requires a `reason_code` per
account (see Banking Circle's Virtual Accounts Reference Data for valid
codes). Closure is irreversible and applies to all currencies linked to
the account — there's no partial closure. Processing has a ~15 minute
delay and pauses daily 18:40–20:55 CET.

`entries` is a list of `%{virtual_account_number: ..., reason_code: ...}`.

# `close_status`

```elixir
@spec close_status(String.t(), client()) ::
  {:ok, map()} | {:error, BankingCircle.Error.t()}
```

Checks closure processing status for a virtual account.

# `customer_details_status`

```elixir
@spec customer_details_status(String.t(), String.t(), client()) ::
  {:ok, map()} | {:error, BankingCircle.Error.t()}
```

Checks the status of a previously-submitted `add_customer_details/2`
update for one virtual account.

# `list`

```elixir
@spec list(
  keyword(),
  client()
) :: {:ok, map()} | {:error, BankingCircle.Error.t()}
```

Lists virtual accounts, optionally filtered (e.g. by `status`, `currency`).

# `order`

```elixir
@spec order(map(), client()) :: {:ok, map()} | {:error, BankingCircle.Error.t()}
```

Orders one or more new virtual accounts. See the moduledoc's confidence
note — this endpoint path/payload should be confirmed against your API
reference before production use.

`attrs` typically needs: `:account_type` (e.g. `"Standard"`, `"POBO"`,
`"COBO"`), `:currency` or `:physical_accounts_list` (to pin specific
Master Account linkage), and `:quantity` for bulk ordering.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
