External advisor
The one outside person your account can give access to in any plan: how to mark them, the limit of one and why they take no seat.
The external advisor is the one person outside your team whom your account lets work on its tax IDs, typically the accountant who keeps your books. The advisor joins your account as a member with grants on the tax IDs you choose, like any other member, with three differences: there is one per account, it exists in any plan and it takes no seat.
This guide covers what the role is, how to give it from the web app and from the API, which plans can manage it only from the web app, what the advisor loses when you retire it and which errors to expect. The advisor is a person inside your account. If the firm works from its own account, use granted access instead, which is a relation between two accounts.
What the role is
| Rule | How it works |
|---|---|
| One per account | At most one member carries the mark and at most one advisor invitation is pending at a time. A second advisor answers 422 external_advisor_already_assigned. |
| Any plan | The web app manages the advisor in every plan. The API and the MCP server do it only where the plan includes the user_management module: see plans without user management. |
| No seat | The user limit of the plan counts the owner, the admins and the members without the advisor. Inviting the advisor checks no limit, neither when you send the invitation nor when the person accepts it, so an account that reached its limit still gets its advisor. |
Always a member | The advisor is never an admin and never the owner. Making the advisor an admin answers 422 business_rule_violation with the subcode external_advisor_must_be_member, and the ownership cannot be transferred to the advisor. |
| Grants like any member | The advisor reaches only the tax IDs with a grant, at level view or operate. The grants are edited like those of any other member: see change what the advisor reaches. |
| Marked by hand | An owner or an admin of the account sets the mark by hand. Factuarea never infers it. |
In the API, a member tells whether it is the advisor in the external_advisor field. The member list has no filter for it: page through GET /v1/accounts/{account}/members and look for the member with external_advisor: true, of which there is at most one. For an owner or an admin who reads it, its permissions block says can_change_role: false and can_transfer_ownership: false, while can_remove and can_edit_grants stay true.
Give the advisor access
The advisor comes in through an invitation sent from the web app. An owner or an admin opens the External advisor section of the user management page, chooses Invite advisor, writes the email, picks the tax IDs with their level (view or operate) and decides whether Factuarea sends the email or shows the link once for you to copy. The person accepts it like any other invitation and joins as a member with the mark.
The API and the MCP server never create the invitation of the advisor. POST /v1/accounts/{account}/invitations and the tool create_account_invitation have no external_advisor field, so what they send is an ordinary invitation: it takes a seat and never carries the mark.
To bring the advisor in through the API, invite the person as a member and mark the member once they have joined. On an account that reached its user limit that first invitation answers 422 business_rule_violation, so use the web app.
- One at a time. A second pending invitation of the advisor answers
422 external_advisor_already_assigned, and so does inviting the advisor when the account already has one. An ordinary pending invitation does not get in the way. The same code answers when the person accepts and another advisor took the place in the meantime. - An expired invitation still holds the place. An advisor invitation that expired without being revoked keeps counting until you revoke it or invite another advisor, which revokes it for you.
- Follow it from the API. A pending invitation of the advisor is listed by
GET /v1/accounts/{account}/invitationswithexternal_advisor: true, and the operations that revoke and resend an invitation act on it like on any other.
Mark a member as the advisor
To turn an existing member into the advisor, send external_advisor to the member:
| Channel | Operation | Scope |
|---|---|---|
| API | PATCH /v1/accounts/{account}/members/{member} with external_advisor | members:write |
| MCP | update_account_member with member_id and external_advisor | members:write |
{member} and member_id are the id of the member, the one the member list publishes, not the identifier of the person. The MCP tools of the team need an API key: the OAuth channel does not reach them.
curl -X PATCH "https://api.factuarea.com/v1/accounts/$ACCOUNT_ID/members/$MEMBER_ID" \
-H "Authorization: Bearer $FACTUAREA_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ "external_advisor": true }'{
"data": {
"id": "01933a50-2c41-7a8b-9c0d-1e2f3a4b5c03",
"object": "account_member",
"name": "Laura Vidal",
"email": "laura@despacho.example",
"role": "member",
"external_advisor": true,
"grants": [
{
"object": "account_member_grant",
"company_id": "0193f1a0-5c2e-7b41-8d06-9a1e2f3c4d5e",
"level": "view"
}
],
"permissions": {
"can_change_role": false,
"assignable_roles": [],
"can_remove": true,
"can_transfer_ownership": false,
"can_edit_grants": true
}
}
}- Who can. The person who issued the credential must be an owner or an admin of the account when you call, with the
user_managementsection available, and the scope of the credential must cover every tax ID of the account, because the mark changes how many seats the whole team takes. Otherwise the answer is403 forbidden_action. - Body.
external_advisor,roleor both, and at least one. Both changes apply together or not at all: the mark is removed first, then the role changes and the mark is set last. Promoting the advisor toadmintherefore takes one request,{ "role": "admin", "external_advisor": false }, and it needs a free seat, as unmarking explains. - Marking. Only a
membercan be marked, and only when the account has no other advisor. Marking the current advisor again changes nothing. The member keeps its grants and stops taking a seat. A pending advisor invitation does not stop you from marking a member, but it will answer422 external_advisor_already_assignedwhen its person accepts. - Not announced. Marking and unmarking send no email and publish no event.
Plans without user management
Managing the team through the API and the MCP server belongs to the user_management module, which the empresario and enterprise plans include and emprendedor does not. Without it the members:* and invitations:* scopes cannot be assigned to a key and the tools of the team are out of reach, so the advisor is managed only from the web app. On such a plan GET /v1/me leaves those scopes out of the effective scopes of the key.
The web app has no such limit for the advisor. In any plan an owner or an admin can invite the advisor, see them with their grants, change those grants, resend or cancel the invitation, remove the advisor and remove the mark. Everything else about managing the team stays locked.
That is a declared exclusion, not a gap: it lets an account with a plan without team management give access to its accountant. The scope and limitations guide lists it with the other things the API does not cover.
Change what the advisor reaches
The grants of the advisor are those of any member: in the web app, in the same section where you invited them, and in the API and the MCP server with the member operations, which need the user_management module.
| Channel | Operation | Scope |
|---|---|---|
| API | PUT /v1/accounts/{account}/members/{member}/grants/{company} with level | members:write |
| API | DELETE /v1/accounts/{account}/members/{member}/grants/{company} | members:write |
| MCP | set_account_member_grant, revoke_account_member_grant | members:write |
Revoking a grant closes that tax ID to the advisor in the web app, the API and the MCP server, and lowering it from operate to view makes it read-only there. Both lower the API keys of the person on that tax ID accordingly, and a key never gains a level because the grant goes back up. To let the advisor see less without retiring them, revoke or lower the grant.
Retire the advisor
There are two ways to end the role, and they do different things. Choose by whether the person keeps working in your account.
| You want | Web app | API | MCP |
|---|---|---|---|
| Take the person out of the account | Remove advisor | DELETE /v1/accounts/{account}/members/{member} | delete_account_member |
| Keep the person as a member without the mark | Remove advisor tag | PATCH /v1/accounts/{account}/members/{member} with external_advisor: false | update_account_member with external_advisor: false |
Remove the advisor from the account
curl -X DELETE "https://api.factuarea.com/v1/accounts/$ACCOUNT_ID/members/$MEMBER_ID" \
-H "Authorization: Bearer $FACTUAREA_KEY" \
-H "Idempotency-Key: $(uuidgen)"The answer is 204 with no body. The operation needs members:write, an owner or an admin with the user_management section available as the issuer and a credential that covers every tax ID of the account. It is irreversible, so Idempotency-Key is required and a call without it answers 422 idempotency_key_required. The MCP tool delete_account_member is irreversible too and takes an idempotency_key. This is what the advisor loses, the same in the three channels:
- Every tax ID of the account, at once. Access is a single fact, the membership, so removing it closes the web app, the API and the MCP server together. There is no access per channel left to clean up.
- Their sessions. The sessions bound to any tax ID of the account, or to the sandbox of one, are revoked. Their sessions anywhere else stay.
- Their API keys. The keys of the person for this account lose the tax IDs of the account, and a key left with none is revoked.
- Their user, only if nothing else links them. The person is deleted when they have no other account, no employee membership and no company outside this account. Otherwise they keep their user and everything else.
- No way back. Their grants are gone. To give access again you invite the person anew from the web app, with grants from scratch. The place of the advisor is free as soon as the call returns.
If you only want the advisor to see less, lower their grants instead.
Keep the person and remove the mark
Unmarking leaves the person in the account as a member with the same grants, and from then on they take a seat. The plan therefore needs a free one: without it the answer is 422 business_rule_violation with param external_advisor, and nothing changes. Free a seat or remove the advisor instead. Unmarking a member who is not the advisor changes nothing.
Events
Removing the advisor is a membership change like any other: it publishes account.member_removed to the account webhook endpoints that subscribe to it, and accepting the invitation publishes account.member_added. Marking and unmarking publish nothing, and the payload of the account.member_* events carries the role but not the mark, so read external_advisor from the member when you need it. Account webhooks describes the endpoints and the envelope.
Errors
| Code | Status | When |
|---|---|---|
external_advisor_already_assigned | 422 | The account already has an advisor and you mark or invite another, it already has a pending advisor invitation and you send a second one, or you accept an invitation after another advisor took the place. |
business_rule_violation | 422 | The advisor would not be a member (subcode external_advisor_must_be_member), or removing the mark needs a seat the plan does not have (param external_advisor). |
forbidden_action | 403 | The issuer is not an owner or an admin of the account with the user_management section available, or the credential does not cover every tax ID of the account. |
member_not_found | 404 | {member} does not exist, is malformed or belongs to another account, with the same body in the three cases. |
live_credential_required | 403 | A fact_test_ key tries to write. Reading the team works with it. |
idempotency_key_required | 422 | The removal DELETE arrives without Idempotency-Key. |
Related
the roles, the grants, the members and the invitations of the account.
let another account reach some or all of your tax IDs.
receive account.member_added and account.member_removed at one endpoint.
the plan, the charge and the cap when your account adds a tax ID.