# Account (/reference/account)

## Who you are, and your merchants

`GET /v1/account`

Console sessions only — and the one read that works BEFORE you have a merchant. The signed-in person, their account (individual or business; null until sign-up's last step), every merchant they are in with their role and mode, and which merchant this session acts in.

Every other `/v1/*` route acts in the active merchant. A session that has not verified with Telegram gets `401 telegram_required` from them (`telegram` says where that stands); one that is in no merchant gets `401 no_merchant` until `PUT /v1/account` has run.

### Responses

- `200` — The account and its merchants.
  - `object` (required, string, one of: account_home)
  - `user` (required, object)
    - `id` (required, string)
    - `name` (required, string)
    - `email` (required, string (email))
  - `account` (required, object) — Null until sign-up's last step (`PUT /v1/account`) ran.
    - `object` (required, string, one of: account)
    - `account_type` (required, string, one of: individual, business) — Asked at sign-up. Individual → business is self-serve; the reverse is a support conversation.
    - `legal_name` (required, string | null) — A business's registered name; null for an individual.
    - `country` (required, string | null) — ISO 3166-1 alpha-2 — an individual's nationality, a business's country of registration.
    - `phone` (required, string | null)
    - `kyc_status` (required, string, one of: unstarted, pending, approved, rejected)
    - `kyb_status` (required, string | null, one of: unstarted, pending, approved, rejected, null) — Null for an individual.
    - `created_at` (required, string (date-time))
  - `telegram` (optional, object)
    - `required` (required, boolean) — Whether this deployment asks for the step at all.
    - `verified` (required, boolean) — True once the account has verified with Telegram (or staff waived the step). Until then every other route answers `401 telegram_required`.
    - `waived` (required, boolean) — True when staff waived the step rather than a Telegram login passing it.
    - `phone` (required, string | null) — The phone number Telegram vouched for, E.164.
    - `username` (required, string | null) — The Telegram username without the @, when the person has one.
    - `display_name` (required, string | null)
    - `linked_at` (required, string | null (date-time))
  - `merchants` (required, array)
    - `object` (required, string, one of: merchant_summary)
    - `billing_account_id` (required, string (uuid)) — Who pays: the billing account's public id.
    - `billing_shared` (required, boolean) — True when this is the owner's shared plan and balance; false for a merchant with billing of its own.
    - `id` (required, string (uuid)) — The merchant's public id — the same `merchant_id` as `GET /v1/merchant/me`.
    - `display_name` (required, string)
    - `logo_url` (required, string | null)
    - `website_url` (required, string | null)
    - `domain` (required, string | null) — The VERIFIED domain, or null.
    - `network` (required, string, one of: testnet, mainnet)
    - `status` (required, string, one of: active, paused, suspended)
    - `role` (required, string, one of: owner, admin, finance, developer, viewer)
    - `active` (required, boolean) — Whether this session acts in this merchant right now.
    - `created_at` (required, string (date-time))
  - `active_merchant_id` (required, string | null (uuid))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## Finish sign-up, or edit your account

`PUT /v1/account`

**With no account yet:** `account_type` is required. Creates the account and — if you are in no merchant and have verified with Telegram — your first merchant, named `merchant_name` (else your business name, else your own name), and makes it active. Before the Telegram step only the account row is written; the merchant follows when `POST /v1/account/telegram/complete` lands. This is sign-up's last step; the console repeats it at `/welcome` if it never ran.

**With an account:** updates `legal_name`, `country` and `phone`. `account_type` may go individual → business (KYB then starts `unstarted`); business → individual is refused with `409 downgrade_not_self_service`. If you are still in no merchant (the first call made the account but not the merchant), this call makes it.

### Request body (required)

- `account_type` (optional, string, one of: individual, business)
- `legal_name` (optional, string | null)
- `country` (optional, string | null) — ISO 3166-1 alpha-2.
- `phone` (optional, string | null)
- `merchant_name` (optional, string) — Your first merchant's trading name. Read only while you are in no merchant.

### Responses

- `200` — The account and its merchants after the change.
  - `object` (required, string, one of: account_home)
  - `user` (required, object)
    - `id` (required, string)
    - `name` (required, string)
    - `email` (required, string (email))
  - `account` (required, object) — Null until sign-up's last step (`PUT /v1/account`) ran.
    - `object` (required, string, one of: account)
    - `account_type` (required, string, one of: individual, business) — Asked at sign-up. Individual → business is self-serve; the reverse is a support conversation.
    - `legal_name` (required, string | null) — A business's registered name; null for an individual.
    - `country` (required, string | null) — ISO 3166-1 alpha-2 — an individual's nationality, a business's country of registration.
    - `phone` (required, string | null)
    - `kyc_status` (required, string, one of: unstarted, pending, approved, rejected)
    - `kyb_status` (required, string | null, one of: unstarted, pending, approved, rejected, null) — Null for an individual.
    - `created_at` (required, string (date-time))
  - `telegram` (optional, object)
    - `required` (required, boolean) — Whether this deployment asks for the step at all.
    - `verified` (required, boolean) — True once the account has verified with Telegram (or staff waived the step). Until then every other route answers `401 telegram_required`.
    - `waived` (required, boolean) — True when staff waived the step rather than a Telegram login passing it.
    - `phone` (required, string | null) — The phone number Telegram vouched for, E.164.
    - `username` (required, string | null) — The Telegram username without the @, when the person has one.
    - `display_name` (required, string | null)
    - `linked_at` (required, string | null (date-time))
  - `merchants` (required, array)
    - `object` (required, string, one of: merchant_summary)
    - `billing_account_id` (required, string (uuid)) — Who pays: the billing account's public id.
    - `billing_shared` (required, boolean) — True when this is the owner's shared plan and balance; false for a merchant with billing of its own.
    - `id` (required, string (uuid)) — The merchant's public id — the same `merchant_id` as `GET /v1/merchant/me`.
    - `display_name` (required, string)
    - `logo_url` (required, string | null)
    - `website_url` (required, string | null)
    - `domain` (required, string | null) — The VERIFIED domain, or null.
    - `network` (required, string, one of: testnet, mainnet)
    - `status` (required, string, one of: active, paused, suspended)
    - `role` (required, string, one of: owner, admin, finance, developer, viewer)
    - `active` (required, boolean) — Whether this session acts in this merchant right now.
    - `created_at` (required, string (date-time))
  - `active_merchant_id` (required, string | null (uuid))
- `400` — `account_type_required` on a first call without it; `invalid_body`.
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `409` — `downgrade_not_self_service`.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## Another merchant

`POST /v1/account/merchants`

Another website, brand or integration under the same account: its own project, API keys, webhooks and domain, with you as its owner. By default it SHARES your plan and prepaid balance (one top-up for every merchant) and, if that plan is already active, it is live from the start; `billing: "separate"` gives it a plan, balance and funding addresses of its own, starting in test mode. Made active for this session. Needs an account (`409 account_required`).

### Request body (required)

- `display_name` (required, string)
- `website_url` (optional, string | null) — http(s) only; unverified, shown to payers as such.
- `billing` (optional, string, one of: shared, separate) — Who pays — see above.

### Responses

- `201` — The account and its merchants, the new one active.
  - `object` (required, string, one of: account_home)
  - `user` (required, object)
    - `id` (required, string)
    - `name` (required, string)
    - `email` (required, string (email))
  - `account` (required, object) — Null until sign-up's last step (`PUT /v1/account`) ran.
    - `object` (required, string, one of: account)
    - `account_type` (required, string, one of: individual, business) — Asked at sign-up. Individual → business is self-serve; the reverse is a support conversation.
    - `legal_name` (required, string | null) — A business's registered name; null for an individual.
    - `country` (required, string | null) — ISO 3166-1 alpha-2 — an individual's nationality, a business's country of registration.
    - `phone` (required, string | null)
    - `kyc_status` (required, string, one of: unstarted, pending, approved, rejected)
    - `kyb_status` (required, string | null, one of: unstarted, pending, approved, rejected, null) — Null for an individual.
    - `created_at` (required, string (date-time))
  - `telegram` (optional, object)
    - `required` (required, boolean) — Whether this deployment asks for the step at all.
    - `verified` (required, boolean) — True once the account has verified with Telegram (or staff waived the step). Until then every other route answers `401 telegram_required`.
    - `waived` (required, boolean) — True when staff waived the step rather than a Telegram login passing it.
    - `phone` (required, string | null) — The phone number Telegram vouched for, E.164.
    - `username` (required, string | null) — The Telegram username without the @, when the person has one.
    - `display_name` (required, string | null)
    - `linked_at` (required, string | null (date-time))
  - `merchants` (required, array)
    - `object` (required, string, one of: merchant_summary)
    - `billing_account_id` (required, string (uuid)) — Who pays: the billing account's public id.
    - `billing_shared` (required, boolean) — True when this is the owner's shared plan and balance; false for a merchant with billing of its own.
    - `id` (required, string (uuid)) — The merchant's public id — the same `merchant_id` as `GET /v1/merchant/me`.
    - `display_name` (required, string)
    - `logo_url` (required, string | null)
    - `website_url` (required, string | null)
    - `domain` (required, string | null) — The VERIFIED domain, or null.
    - `network` (required, string, one of: testnet, mainnet)
    - `status` (required, string, one of: active, paused, suspended)
    - `role` (required, string, one of: owner, admin, finance, developer, viewer)
    - `active` (required, boolean) — Whether this session acts in this merchant right now.
    - `created_at` (required, string (date-time))
  - `active_merchant_id` (required, string | null (uuid))
- `400` — `invalid_body`.
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `409` — `account_required`.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## Begin verifying with Telegram

`POST /v1/account/telegram/start`

Console sessions only. Every account verifies with Telegram — and shares the phone number on its Telegram — before it can set up a merchant, pay or create anything; until then every other route answers `401 telegram_required` (`GET /v1/account` and these two excepted).

Returns the Telegram login URL to send the browser to. Telegram brings the browser back to the console, which calls `POST /v1/account/telegram/complete` with what it was given. A login attempt lives ten minutes.

### Responses

- `200` — Where to send the browser.
  - `url` (required, string (uri))
  - `expires_at` (required, string (date-time))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — `telegram_unconfigured` — this deployment does not ask for the step.

## Finish verifying with Telegram

`POST /v1/account/telegram/complete`

Console sessions only. The console posts the `code` and `state` Telegram returned (or `error` and `state` when the person declined). On success the account is verified and, if sign-up's answers were already given and the person is in no merchant, the first merchant is made and activated in the same call.

One Telegram per account and one account per Telegram: a Telegram or phone number already verifying another account is refused. An anonymous (+888) number is refused. A Telegram identity behind a banned account is refused.

### Request body (required)

- `state` (required, string)
- `code` (optional, string | null)
- `error` (optional, string | null) — Telegram's `error` query parameter, when it sent one instead of a code.

### Responses

- `200` — The account, verified — with its first merchant when sign-up was waiting on this step.
  - `object` (required, string, one of: account_home)
  - `user` (required, object)
    - `id` (required, string)
    - `name` (required, string)
    - `email` (required, string (email))
  - `account` (required, object) — Null until sign-up's last step (`PUT /v1/account`) ran.
    - `object` (required, string, one of: account)
    - `account_type` (required, string, one of: individual, business) — Asked at sign-up. Individual → business is self-serve; the reverse is a support conversation.
    - `legal_name` (required, string | null) — A business's registered name; null for an individual.
    - `country` (required, string | null) — ISO 3166-1 alpha-2 — an individual's nationality, a business's country of registration.
    - `phone` (required, string | null)
    - `kyc_status` (required, string, one of: unstarted, pending, approved, rejected)
    - `kyb_status` (required, string | null, one of: unstarted, pending, approved, rejected, null) — Null for an individual.
    - `created_at` (required, string (date-time))
  - `telegram` (optional, object)
    - `required` (required, boolean) — Whether this deployment asks for the step at all.
    - `verified` (required, boolean) — True once the account has verified with Telegram (or staff waived the step). Until then every other route answers `401 telegram_required`.
    - `waived` (required, boolean) — True when staff waived the step rather than a Telegram login passing it.
    - `phone` (required, string | null) — The phone number Telegram vouched for, E.164.
    - `username` (required, string | null) — The Telegram username without the @, when the person has one.
    - `display_name` (required, string | null)
    - `linked_at` (required, string | null (date-time))
  - `merchants` (required, array)
    - `object` (required, string, one of: merchant_summary)
    - `billing_account_id` (required, string (uuid)) — Who pays: the billing account's public id.
    - `billing_shared` (required, boolean) — True when this is the owner's shared plan and balance; false for a merchant with billing of its own.
    - `id` (required, string (uuid)) — The merchant's public id — the same `merchant_id` as `GET /v1/merchant/me`.
    - `display_name` (required, string)
    - `logo_url` (required, string | null)
    - `website_url` (required, string | null)
    - `domain` (required, string | null) — The VERIFIED domain, or null.
    - `network` (required, string, one of: testnet, mainnet)
    - `status` (required, string, one of: active, paused, suspended)
    - `role` (required, string, one of: owner, admin, finance, developer, viewer)
    - `active` (required, boolean) — Whether this session acts in this merchant right now.
    - `created_at` (required, string (date-time))
  - `active_merchant_id` (required, string | null (uuid))
- `400` — `telegram_state_invalid` — expired or already used; start again. `invalid_body`.
- `401` — Missing, malformed, expired or revoked API key.
- `403` — `account_banned` — this Telegram or phone is behind a closed account.
- `409` — `telegram_declined`, `telegram_phone_required`, `telegram_phone_anonymous`, `telegram_phone_invalid`, `telegram_in_use`, `telegram_phone_in_use`, `telegram_already_linked`.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — `telegram_unconfigured`, `telegram_exchange_failed`, `telegram_token_invalid` — try again.

## Switch to one of your merchants

`POST /v1/account/merchants/{id}/activate`

Makes `id` (a merchant's public id from `GET /v1/account`) the merchant this session acts in — every other route follows. You must be a member of it. Better Auth's `organization/set-active` does the write.

### Parameters

- `id` (path, required, string (uuid))

### Responses

- `200` — The account and its merchants, the chosen one active.
  - `object` (required, string, one of: account_home)
  - `user` (required, object)
    - `id` (required, string)
    - `name` (required, string)
    - `email` (required, string (email))
  - `account` (required, object) — Null until sign-up's last step (`PUT /v1/account`) ran.
    - `object` (required, string, one of: account)
    - `account_type` (required, string, one of: individual, business) — Asked at sign-up. Individual → business is self-serve; the reverse is a support conversation.
    - `legal_name` (required, string | null) — A business's registered name; null for an individual.
    - `country` (required, string | null) — ISO 3166-1 alpha-2 — an individual's nationality, a business's country of registration.
    - `phone` (required, string | null)
    - `kyc_status` (required, string, one of: unstarted, pending, approved, rejected)
    - `kyb_status` (required, string | null, one of: unstarted, pending, approved, rejected, null) — Null for an individual.
    - `created_at` (required, string (date-time))
  - `telegram` (optional, object)
    - `required` (required, boolean) — Whether this deployment asks for the step at all.
    - `verified` (required, boolean) — True once the account has verified with Telegram (or staff waived the step). Until then every other route answers `401 telegram_required`.
    - `waived` (required, boolean) — True when staff waived the step rather than a Telegram login passing it.
    - `phone` (required, string | null) — The phone number Telegram vouched for, E.164.
    - `username` (required, string | null) — The Telegram username without the @, when the person has one.
    - `display_name` (required, string | null)
    - `linked_at` (required, string | null (date-time))
  - `merchants` (required, array)
    - `object` (required, string, one of: merchant_summary)
    - `billing_account_id` (required, string (uuid)) — Who pays: the billing account's public id.
    - `billing_shared` (required, boolean) — True when this is the owner's shared plan and balance; false for a merchant with billing of its own.
    - `id` (required, string (uuid)) — The merchant's public id — the same `merchant_id` as `GET /v1/merchant/me`.
    - `display_name` (required, string)
    - `logo_url` (required, string | null)
    - `website_url` (required, string | null)
    - `domain` (required, string | null) — The VERIFIED domain, or null.
    - `network` (required, string, one of: testnet, mainnet)
    - `status` (required, string, one of: active, paused, suspended)
    - `role` (required, string, one of: owner, admin, finance, developer, viewer)
    - `active` (required, boolean) — Whether this session acts in this merchant right now.
    - `created_at` (required, string (date-time))
  - `active_merchant_id` (required, string | null (uuid))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `404` — `merchant_not_found` — not one of yours.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## Every merchant, one screen

`GET /v1/account/overview`

Console sessions only. For every merchant you are in: its balance (own wallet + service wallet at spot — what you can use, not what is owed to customers), plan, customers and deposit addresses; the prepaid fee balance per billing account (a shared account appears once); and one activity feed — deposits, paid invoices, withdrawals — across all of them, newest first, each row tagged with its merchant.

A merchant whose wallets could not be read comes back with `wallets: null` and is counted in `totals.unavailable`, never as $0. The plan's history window applies per merchant.

### Responses

- `200` — Every merchant, the billing accounts, the totals and the feed.
  - `object` (required, string, one of: account_overview)
  - `merchants` (required, array)
    - `object` (required, string, one of: merchant_overview)
    - `id` (required, string (uuid))
    - `display_name` (required, string)
    - `logo_url` (required, string | null)
    - `website_url` (required, string | null)
    - `domain` (required, string | null) — The VERIFIED domain, or null.
    - `network` (required, string, one of: testnet, mainnet)
    - `status` (required, string, one of: active, paused, suspended)
    - `role` (required, string, one of: owner, admin, finance, developer, viewer)
    - `active` (required, boolean)
    - `billing_account_id` (required, string (uuid))
    - `billing_shared` (required, boolean)
    - `plan` (required, object)
      - `key` (required, string)
      - `name` (required, string)
      - `status` (required, string, one of: pending, active)
    - `wallets` (required, object) — The own wallet and the service wallet at spot — what the merchant can use. Null when either could not be read; never $0 for a failed read.
      - `own_usd_cents` (required, string)
      - `service_usd_cents` (required, string)
      - `total_usd_cents` (required, string)
      - `unpriced` (required, integer) — Coins held that have no price right now — excluded from the totals.
    - `customers` (required, integer | null)
    - `addresses` (required, integer | null) — Customer deposit addresses issued.
    - `created_at` (required, string (date-time))
  - `billing_accounts` (required, array)
    - `object` (required, string, one of: billing_account_summary)
    - `id` (required, string (uuid))
    - `shared` (required, boolean) — True for the person's default account, drawn on by every merchant without billing of its own.
    - `plan` (required, string)
    - `plan_name` (required, string)
    - `plan_status` (required, string, one of: pending, active)
    - `balance_cents` (required, string) — The prepaid fee balance, USD cents.
    - `merchant_ids` (required, array, of string (uuid))
  - `totals` (required, object)
    - `balance_usd_cents` (required, string) — Sum over LIVE merchants whose wallets were read.
    - `prepaid_cents` (required, string) — Sum over billing accounts.
    - `unpriced` (required, integer)
    - `unavailable` (required, integer) — Merchants left out of the total because a wallet could not be read.
    - `test_mode` (required, integer) — Test-mode merchants, left out of the total: their coins are not real money.
    - `merchants` (required, integer)
  - `activity` (required, array) — Newest first, across every merchant. Null when the feed could not be assembled — render a failure, not an empty list.
    - `object` (required, string, one of: activity)
    - `kind` (required, string, one of: deposit, invoice, payout)
    - `id` (required, string)
    - `ref` (required, string | null) — The MolnPay ID where the record has one (deposits, withdrawals); invoices carry none.
    - `merchant` (required, object) — The tag: which merchant this row belongs to.
      - `id` (required, string (uuid))
      - `display_name` (required, string)
    - `at` (required, string (date-time))
    - `status` (required, string)
    - `title` (required, string)
    - `subtitle` (required, string | null)
    - `chain` (required, string | null)
    - `asset` (required, object)
      - `symbol` (required, string)
      - `decimals` (required, integer)
      - `logo_url` (required, string | null)
    - `amount_decimal` (required, string | null)
    - `value_usd_cents` (required, string | null)
    - `fiat` (required, object) — An invoice's price in the currency it was raised in, minor units.
      - `amount_minor` (required, string)
      - `currency` (required, string)
    - `direction` (required, string, one of: in, out)
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.