---
title: "Set the account owner"
method: PUT
path: "/v1/accounts/{account_id}/owner"
tags: ["Members"]
---

# Set the account owner

`PUT /v1/accounts/{account_id}/owner`

## Request

- Base URL: `https://app.beel.es/api`
- URL: `https://app.beel.es/api/v1/accounts/{account_id}/owner`
- Auth: API key in cookie `BEEL_SESSION`

Makes the member in the body the account's `OWNER` and steps the calling owner down to
`ADMIN`, so the account always keeps exactly one owner.

- **Repeatable:** it states the desired owner rather than performing a transfer, so
  repeating the same call once that member already owns the account returns the same
  `204` instead of failing.
- **Credentials:** unlike the rest of this API, this operation is available only from a
  signed-in dashboard session. No API key, live or test, can perform it, whatever scopes
  it holds.
- **From an integration:** to hand an account over to its holder, issue a claim token with
  `POST /v1/accounts/{account_id}/claim-tokens` instead.

## Headers

- `Idempotency-Key` string

## Request body

- SetAccountOwnerRequest: The member who is to own the account.
  - `member_id` string, uuid, required: Membership UUID of the member who becomes OWNER.

## Response `204`

Ownership set successfully

## Other responses

- `400`: Bad request. From a dashboard session, a `BeeL-Environment` header whose value is not a known environment answers `ENVIRONMENT_HEADER_INVALID`, with the header named in `error.details` (`{"BeeL-Environment": "invalid"}`); it is never read as production. `BUSINESS_RULE_VIOLATION` is the generic answer to an operation the resource does not admit in its current state when that state has no code of its own. It carries no `details`; read the resource again before retrying.
- `401`: Missing or invalid authentication. Like every other error, `message`/`detail` is localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English when the header is missing or asks for none of those.
- `403`: Every cause listed under the plain `403` above, plus the one that governs this operation: `OPERATION_REQUIRES_SESSION` — "This operation is only available from the web session; it cannot be performed with an API key or OAuth." It is returned to **every** machine credential, live key included, whatever scopes it holds, and before any other check, so it is not a permission you can be granted and retrying with a different key never helps. The operation is reserved to a signed-in human in the dashboard because a leaked key must not be able to take an account over. From the session, two more: `OWNER_ROLE_RESERVED`, when the session belongs to an `ADMIN`, since only an `OWNER` hands ownership over, and `MEMBER_MANAGEMENT_FORBIDDEN`, when the session's role does not manage members.
- `404`: `MEMBER_NOT_FOUND` — no member with that id belongs to the account. Membership ids are not shared between accounts, so a member of another account answers the same way.
- `429`: Rate limit exceeded. `RATE_LIMIT_EXCEEDED` when the request rate of your credential is over its limit; `TOO_MANY_REQUESTS` when an email the operation sends is held back because too many went out to that recipient in a short time. Either way, retry after the `Retry-After` seconds. `QUOTA_EXCEEDED` is the other `429`: the operation would go over a quota of your plan for the current period (issued invoices, for instance). Retrying does not help until the quota resets or the plan changes. `error.details` carries `feature_code`, `current_usage`, `quota_limit` and `reset_date`, and `RateLimit-Reset` the seconds until the reset when it is known.
- `500`: Internal server error
- `default`: Any status code the operation does not list above. Every operation declares it, so a generated client always has a branch to fall into and never loses the cause of a failure it did not anticipate. This is where the transport-level answers land — `405`, `406`, `415` and `429` — together with any status a future version of the API starts returning. All of them carry the same error envelope as the codes listed explicitly, so `error.code` is what tells them apart: switching on the status code alone is not enough. See «Transport-level errors» in the API description for when each one is produced. A `402` carrying `SUBSCRIPTION_REQUIRED` lands here when the account has no active subscription. `error.details` says why and what to do: `current_status` (absent if it never had one), `required_permission` and `action`. A `503` carrying `SERVICE_UNAVAILABLE` lands here too, with a `Retry-After` header: a dependency of BeeL itself (the database, the email provider) was momentarily unavailable and nothing was done. Retry after those seconds. A `502` carrying `EXTERNAL_SERVICE_ERROR` also lands here: an outbound integration the operation depends on failed or did not answer in time. It is a transient condition — retry with the same `Idempotency-Key` where the operation accepts one. One exception to the envelope: a failure of the network edge that never reaches the application (`502`, `503`, `504`, `524`) is generated by Cloudflare and its body is not BeeL's — it may not even be JSON. Treat those as "no answer", and retry.

---

[API](https://skmtc.dev/beel/apis/beel-public-api.md) · [All operations](https://skmtc.dev/beel/apis/beel-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/beel/apis/beel-public-api/revisions/ffbc0ae31f79?raw)
