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

# Create Virtual Account Group

> Open a virtual account group for an account you own and start its onboarding

Any customer can open a virtual account group on an account it owns, provided the API key carries the `virtual_accounts` scope: on your own account, or, if you are a platform customer, on any of your end-customer accounts and on your own fee-collection account. The account needs an identity profile before onboarding can progress, and a business account also needs an associated person marked as a signer.

Opens a group of the given type for an account you own. The body names a `type` from [List Group Types](/fx/api-reference/virtual-account-groups/list-group-types).

There is **no** `Idempotency-Key` header on this endpoint. It is idempotent on the account and the group type instead: posting the same `type` for the same account twice returns the group that already exists. The first call returns `201`, a call that reuses an existing group returns `200`. Branch on the status code, or compare the returned `id` with the one you already hold.

Requires an API key with `write` access on the `virtual_accounts` scope, which is separate from `accounts`.

## What the account needs first

Onboarding runs on the account's identity, so the account needs an identity profile before it can progress. Set it with [Update Account](/fx/api-reference/accounts/update-account-identity). That call also fixes the account's `type`, `business` or `individual`, which decides what else is required.

### Business accounts

A business agreement must be signed by an authorised signer, so the account needs at least one associated person with `is_signer: true`. Add them with [Create Associated Person](/fx/api-reference/associated-persons/create-associated-person). That person's id is then **required** as `signer_id` on [Submit Agreement Actions](/fx/api-reference/virtual-account-groups/submit-agreement-actions).

### Individual accounts

Individual accounts have no associated persons at all: an individual account signs as itself. `signer_id` must be **omitted** from [Submit Agreement Actions](/fx/api-reference/virtual-account-groups/submit-agreement-actions); sending one is rejected.

## Opening a group before the identity profile is set

You do not have to wait for the identity profile. Opening a group on an account that has none succeeds and returns `201` like any other create. The group carries a requirement naming what is missing, which [Get Virtual Account Group](/fx/api-reference/virtual-account-groups/get-group) returns:

| Field | Value |
| - | - |
| `key` | `account_profile.required` |
| `type` | `account_profile` |
| `label` | `Add the Account identity profile` |
| `reason` | `Set the Account identity before onboarding can start` |

Clear it the way you clear any other requirement: set the identity profile with [Update Account](/fx/api-reference/accounts/update-account-identity), then poll. That resumes onboarding on its own. There is no second call to this endpoint, and the group keeps the id you already hold.

## Onboarding starts immediately

Creating a group starts provider onboarding, so the group that comes back is not ready to use. A new group starts with `status` `pending` and `onboarding_status` `action_needed`, and two separate gates have to clear before virtual accounts can be created under it: the provider has to approve onboarding (`onboarding_status` `approved`), and Hop has to enable the group (`status` `enabled`).

`onboarding_status` is provider-neutral and provider-authoritative:

| `onboarding_status` | Meaning |
| - | - |
| `action_needed` | Something is outstanding on your side. Read `requirements` on [Get Virtual Account Group](/fx/api-reference/virtual-account-groups/get-group) and clear them. Every new group starts here. |
| `under_review` | Everything asked for has been submitted and the provider is reviewing it. Nothing to do but poll. |
| `approved` | The provider approved onboarding. The group still needs Hop to enable it before it can be used. |
| `rejected` | The provider refused onboarding. Terminal: the group never leaves this state. |
| `suspended` | An approved group was suspended by the provider; `suspended_at` is set. Virtual account creation is blocked until it returns to `approved`. |
| `closed` | Onboarding was closed permanently; `closed_at` is set. Terminal. |

Allowed transitions, as Hop enforces them when the provider reports a change:

* `action_needed` → `under_review`, `approved`, `rejected`, `closed`
* `under_review` → `action_needed`, `approved`, `rejected`, `closed`
* `approved` → `action_needed`, `suspended`, `closed`
* `suspended` → `action_needed`, `approved`, `closed`
* `rejected` and `closed` are terminal

An approved group can drop back to `action_needed` at any time when the provider asks for something new, so keep handling requirements after go-live.

## The onboarding loop

1. Create the group with this endpoint and keep the returned `id`.
2. Read [Get Virtual Account Group](/fx/api-reference/virtual-account-groups/get-group). The detail response carries `requirements`: the outstanding actions, and an `agreements` summary. The create response does not.
3. Clear each requirement. A `document` requirement is satisfied by [Upload Document](/fx/api-reference/virtual-account-groups/upload-document) quoting the requirement `key`; an `account_profile` requirement by [setting or correcting the account's identity](/fx/api-reference/accounts/update-account-identity): `account_profile.required` means no identity profile has been set at all, and an `associated_person` requirement by adding or correcting a person on the account.
4. Accept the pending agreements with [Submit Agreement Actions](/fx/api-reference/virtual-account-groups/submit-agreement-actions), using the ids in `agreements.pending_ids`: [List Agreements](/fx/api-reference/virtual-account-groups/list-agreements) has their titles and content.
5. Poll Get Virtual Account Group until `requirements` is empty, `agreements.status` is `complete` and `onboarding_status` is `approved`. There are no webhook events for group onboarding today, so polling is the only signal.
6. Wait for Hop to enable the group: `status` becomes `enabled` and `enabled_at` is set. Then create virtual accounts with [Create Virtual Account](/fx/api-reference/virtual-accounts/create-virtual-account).

Uploading documents and responding to agreements both nudge onboarding forward on Hop's side, so requirements can change between polls without any further action from you.

## Path Parameters

<ParamField path="account_id" type="string" required>
  The account's external ID (starts with `acct_`). It must belong to your customer: your own account, one of your end-customer accounts, or your fee-collection account.
</ParamField>

## Request Body

<ParamField body="type" type="string" required>
  The group type to open, copied from `type` in [List Group Types](/fx/api-reference/virtual-account-groups/list-group-types) (1-100 characters). A type that is not configured returns `404 VIRTUAL_ACCOUNT_GROUP_NOT_FOUND`. No other body field is accepted.
</ParamField>

## Response

Returns `201` with the new group, or `200` with the existing group when one is already open for this account and type.

The response is the group summary. The same shape [List Virtual Account Groups](/fx/api-reference/virtual-account-groups/list-groups) returns. It carries no `requirements`; call [Get Virtual Account Group](/fx/api-reference/virtual-account-groups/get-group) for those.

<ResponseField name="id" type="string">
  Virtual account group identifier (starts with `vag_`)
</ResponseField>

<ResponseField name="object" type="string">
  Always returns `"virtual_account_group"`
</ResponseField>

<ResponseField name="account_id" type="string">
  Account the group belongs to (starts with `acct_`)
</ResponseField>

<ResponseField name="type" type="string">
  The group type, matching the `type` you sent
</ResponseField>

<ResponseField name="status" type="string">
  Activation state, controlled by Hop: `pending`, `enabled` or `disabled`. A new group is `pending`; Hop moves it to `enabled` once onboarding is approved. Only an `enabled` group whose `onboarding_status` is `approved` can back virtual accounts.
</ResponseField>

<ResponseField name="onboarding_status" type="string">
  KYC/KYB progress: `action_needed`, `under_review`, `approved`, `rejected`, `suspended` or `closed`. See the table above.
</ResponseField>

<ResponseField name="enabled_at" type="string">
  ISO 8601 timestamp when Hop first enabled the group, or `null`
</ResponseField>

<ResponseField name="suspended_at" type="string">
  ISO 8601 timestamp when onboarding most recently became `suspended`, or `null`
</ResponseField>

<ResponseField name="closed_at" type="string">
  ISO 8601 timestamp when onboarding was closed, or `null`
</ResponseField>

<ResponseField name="created" type="string">
  ISO 8601 timestamp when created
</ResponseField>

<ResponseField name="updated" type="string">
  ISO 8601 timestamp when last updated
</ResponseField>

<ResponseField name="created_by" type="string">
  Actor that created the group: the API key id (starts with `ak_`) when opened through this API, otherwise the actor Hop recorded
</ResponseField>

<ResponseField name="updated_by" type="string">
  Actor that last updated the group, or `null`
</ResponseField>

## Errors

| Status | `code` | When |
| - | - | - |
| `403` | `ACCESS_DENIED` | The API key has no `virtual_accounts` scope: the `accounts` scope no longer covers virtual accounts |
| `404` | `RESOURCE_NOT_FOUND` | `account_id` is unknown or belongs to another customer |
| `404` | `VIRTUAL_ACCOUNT_GROUP_NOT_FOUND` | `type` is not one of the types returned by [List Group Types](/fx/api-reference/virtual-account-groups/list-group-types) |
| `422` | `VALIDATION_ERROR` | `type` is missing, empty, longer than 100 characters, or the body carries an unknown field |
| `500` | `VIRTUAL_ACCOUNT_GROUP_ASSIGNMENT_CONFLICT` | The account already holds a group whose stored routing no longer matches Hop's configuration for that type. Contact support; retrying will not clear it. |
| `502` | `GATEWAY_ERROR` | The provider could not start onboarding. The group row already exists, so repeat the same request to resume it. |

## Request Example

```json theme={null}
{
  "type": "business_virtual_accounts"
}
```

## Response Example

```json theme={null}
{
  "id": "vag_7m2k9x4c1b6v3n8q5z0j2p7t",
  "object": "virtual_account_group",
  "account_id": "acct_ka44qsvpo8q3wtzuwfqf0h6u",
  "type": "business_virtual_accounts",
  "status": "pending",
  "onboarding_status": "action_needed",
  "enabled_at": null,
  "suspended_at": null,
  "closed_at": null,
  "created": "2026-01-15T10:00:00Z",
  "updated": "2026-01-15T10:00:00Z",
  "created_by": "ak_3f7k9m2p5r8t1v4x6z0b3n5q",
  "updated_by": null
}
```
