NewProvince is only required for addresses in Spain
BeeL
Get startedMulti-NIFVeriFactuRulesStripeAPI referenceChangelog

Members & grants

Account roles (owner/admin/member), per-company grants with an access level (view/operate), and handing over ownership.


Members are the people with access to an account. Each member has one account role; a MEMBER additionally has per-company grants that decide which NIFs they can see and operate. Where members sit in the model, and when you want a managed account instead, is in the Overview.

Every path on this page hangs off the account — /v1/accounts/{account_id}/members/… — because a membership belongs to the account, not to a NIF. All of them require OWNER or ADMIN of that account (403 MEMBER_MANAGEMENT_FORBIDDEN otherwise), plus the members:read or members:write scope.

Changing people needs your live key. Members and grants are shared between Test and Live, so every write on this page made with a beel_sk_test_ key answers 403 LIVE_CREDENTIAL_REQUIRED. Reading works with either key. See Test and live keys.

Two independent axes

Role and access are not the same question, and confusing them is the usual mistake:

  • Account role — who administers the account. Billing, API keys, inviting people.
  • Access level — how much someone can do with one NIF. Read, or read and write.
account_roleAdministersReaches
OWNERFull control: billing, API keys, members, and handing ownership over. Exactly one per account.Every NIF, implicitly.
ADMINEverything an OWNER can do except handing ownership over.Every NIF, implicitly.
MEMBERNothing. No billing, no keys, no member management.Only the NIFs granted to them, at the level of each grant.

OWNER and ADMIN reach every NIF of the account implicitly. Only a MEMBER is scoped NIF by NIF, through grants, at one of these levels:

access_levelWhat the holder can do
VIEWRead their invoices, customers, products, series and fiscal data.
OPERATEEverything in VIEW, plus creating and editing them. Issuing on their behalf additionally requires a signed fiscal representation from the account holder.

A grant takes VIEW or OPERATE. NONE only exists for managed accounts: a grant that grants nothing is not a grant, so you remove access by deleting the grant, not by downgrading it.

Grants govern people who use the dashboard. API keys are created by an OWNER or ADMIN and act with that reach; a MEMBER cannot create keys.

OWNER/ADMIN cannot receive grants. They already reach everything, so their grant list is always empty. Grants apply to MEMBERs only — trying otherwise is 422 GRANTS_ONLY_FOR_MEMBER.

Who is in the account

GET /v1/accounts/{account_id}/members lists them; GET …/members/{member_id} returns one, in the same shape. Fields and types: List account members.

curl https://app.beel.es/api/v1/accounts/3fa85f64-5717-4562-b3fc-2c963f66afa6/members \
  -H "Authorization: Bearer beel_sk_live_xxx"

Two ids come back and they are not interchangeable:

  • member_id is the handle for every call on this page. It identifies this person in this account.
  • person_id is the stable identity of the human, the same across every account they belong to. Use it to recognise the same person across the accounts you manage — you never pass it to an endpoint.

Each member also carries a permissions block (can_change_role, assignable_roles, can_remove, can_transfer_ownership, can_edit_grants). Drive your UI from it instead of re-implementing the role policy; the API enforces the same rules regardless of what you render.

Grant a member access to one NIF

PUT /v1/accounts/{account_id}/members/{member_id}/grants/{company_id} — members:write, live key. The company is in the path, so the body carries only the level. Returns 200 with the grant:

curl -X PUT \
  https://app.beel.es/api/v1/accounts/3fa85f64-5717-4562-b3fc-2c963f66afa6/members/6f8c1e10-3b2a-4c9d-8e7f-1a2b3c4d5e6f/grants/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer beel_sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{ "access_level": "OPERATE" }'

One call touches one NIF. This PUT creates the grant or changes its level, and leaves the member's other grants exactly as they were. To set up access to three NIFs you make three calls — there is no endpoint that replaces the whole set at once, so a concurrent edit by a colleague can never be silently wiped by your request.

Revoking is the mirror image — DELETE on the same path, 204:

curl -X DELETE \
  https://app.beel.es/api/v1/accounts/3fa85f64-5717-4562-b3fc-2c963f66afa6/members/6f8c1e10-3b2a-4c9d-8e7f-1a2b3c4d5e6f/grants/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer beel_sk_live_xxx"

GET …/members/{member_id}/grants lists what a member currently holds — empty for OWNER/ADMIN. See Grant a member access to a company and Revoke a member's access.

WhenErrorStatus
The target is an OWNER or ADMIN.GRANTS_ONLY_FOR_MEMBER422
The NIF hangs off another account — including one you manage.GRANT_COMPANY_NOT_IN_ACCOUNT422
access_level is NONE or anything other than VIEW / OPERATE.VALIDATION_ERROR422

Change a member's role

PATCH /v1/accounts/{account_id}/members/{member_id} — members:write, live key, body { "account_role": "ADMIN" }. See Change a member's role.

The only assignable roles are ADMIN and MEMBER. OWNER is never accepted here — it returns 422 OWNER_ROLE_NOT_ASSIGNABLE, because ownership moves only through the handover below (from the dashboard), never by setting a role.

Promoting a MEMBER to ADMIN makes their grants irrelevant — they now reach every NIF implicitly. Demoting back to MEMBER restores whatever grants they had, so check them after the change.

The last OWNER cannot be demoted, and DELETE …/members/{member_id} cannot remove them either: the account always keeps exactly one (422 LAST_OWNER_PROTECTED). To step down, hand ownership over first.

Hand over ownership

PUT /v1/accounts/{account_id}/owner is dashboard-only. No API key can hand an account over, a live one included: the call answers 403 OPERATION_REQUIRES_SESSION, so a leaked key can never take the account. The current OWNER does it from Settings → Members; the member becomes OWNER and the caller drops to ADMIN. An ADMIN who tries gets 403 OWNER_ROLE_RESERVED.

Repeating it once that member already owns the account returns the same 204, so a retry after a timeout is safe. See Set the account owner.

Provisioning accounts for others? You do not hand them over with this call: the holder takes ownership by redeeming a claim token.