Team and Security
Custom roles
On Team, create your own roles from scratch or by duplicating an existing one, pick exactly the permission keys they hold, and give them to members.
The five preset roles cover most teams, but not every team works the same way. On the Team plan you can create custom roles: a role with its own name and exactly the permission keys you choose. You might make a "Sales" role that can create and send invoices but never record payments, or a "Collections" role that can send reminders and waive late fees but cannot create documents.
Custom roles work exactly like presets. They are checked on every surface (web app, API, MCP, CLI, connectors and the AI agent), they combine with each member's business scope, and every change to them is audited.
Before you start
- You need the Team plan. On Free, the account has only the fixed Owner and one view-only Accountant, and creating a role returns
feature_locked. See Upgrade to Team. - You need a role that holds
team.manage. The Owner and Admin presets have it by default. - You can only tick keys you hold yourself. Nobody can grant a permission they do not have.
Two ways to create a role
| Method | When to use it |
|---|---|
| From scratch | You want a small, precise role. You start with no keys and tick only what is needed. |
| Duplicate a role | You want something close to an existing role. The copy starts with that role's keys, and you tick or untick from there. You can duplicate a preset or another custom role. |
A custom role has no preset behind it, so it has no Reset to default action. Presets do.
Create a custom role in the web app
Open Settings > Team > Roles
The list shows the Owner (fixed), the four editable presets and any custom roles.
Choose New role, or Duplicate on an existing role
Duplicating copies the source role's keys into the new role. The source role is not changed.
Name the role
Role names are unique in your account, ignoring upper and lower case. "Sales" and "sales" count as the same name.
Tick the permission keys
Keys are grouped by module: businesses, documents, clients, items, payments, rails, senders, templates, reminders, late fees, contracts, time, expenses, reports, accounting, ledger, AI, settings, team, integrations, audit and billing. Keys you do not hold yourself cannot be ticked. account.delete and ownership transfer never appear as options because they belong only to the Owner.
Save, then give the role to members
The role appears in the role picker in Settings > Team for invitations and for existing members. See Members and invitations.
Choosing keys well
A few patterns make roles easier to live with:
- Pair a view key with every action key. Action keys such as
documents.sendare most useful together with the matching view key (documents.view), so the member can see what they act on. Most modules have a.viewkey; include it. - Keep money-moving keys narrow.
payments.refund,payments.auto_charge,documents.voidanddocuments.creditmove money or change records your clients have already seen. Give them only to people who need them. - Use business scope for "where". Do not create one role per business. Create one role for the job and set each member's business scope to the businesses they work on.
- Think about API keys. A member's API keys and MCP tokens can never do more than the member's current role allows. If you give someone a narrow role, their automations are narrow too.
The full list of keys, with what each one unlocks, is on Permission keys. The defaults of each preset are on Roles and permissions.
Edit or delete a custom role
Open the role in Settings > Team > Roles, tick or untick keys, and save. Members on that role get the new permissions on their next request, with no need to sign in again. Their API keys and MCP tokens follow on their next call.
To delete a role, first move every member on it to another role. A role that still has members is refused with role_in_use. Once it is empty, delete it. The Owner role can never be edited or deleted.
Through the API
Create a role from scratch by sending a name and a list of keys, or duplicate one with duplicate_of.
curl -X POST "https://api.freeinvoiceautomation.com/v1/roles" \
-H "Authorization: Bearer $FIA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: role-collections" \
-d '{
"name": "Collections",
"permissions": [
"businesses.view", "documents.view", "clients.view",
"payments.view", "reminders.manage", "late_fees.waive"
]
}'{
"data": {
"id": "0193f2b0-1c2d-7e3f-8a4b-5c6d7e8f9a10",
"name": "Collections",
"preset_key": null,
"is_owner": false,
"is_active": true,
"permissions": [
"businesses.view", "documents.view", "clients.view",
"payments.view", "reminders.manage", "late_fees.waive"
]
}
}Then change the copy with Update a role, and assign it with Update a member by setting the member's role_id.
| Capability | Route | Notes |
|---|---|---|
| Create a role | POST /v1/roles | From scratch, or { "duplicate_of": role_id } |
| Update a role | PATCH /v1/roles/{id} | Not the Owner role |
| Delete a role | DELETE /v1/roles/{id} | Destructive: send "confirm": true over the API; refused while members are on it |
| List roles | GET /v1/roles | All roles in the account |
All four need team.manage and a Team plan.
What happens on a downgrade
If your account moves from Team back to Free, for example after a failed renewal, custom and edited roles are kept but inactive. Every member except the Owner is deactivated, and the Owner can reactivate one member into the free view-only Accountant seat. When you upgrade again, your custom roles come back as they were. Deactivated members are not restored automatically: the Owner reactivates each one in Settings > Team, and they create new API keys.
Audit
Every create, update, duplicate and delete of a role writes an entry in the audit log, with who made the change and the old and new key lists. Entries are written on every plan; viewing them is a Team feature.
Errors
| Code | HTTP | When |
|---|---|---|
feature_locked | 403 | The account is on Free. |
permission_denied | 403 | Your role does not hold team.manage. |
permission_not_grantable | 403 | You ticked a key you do not hold, or an Owner-only key. |
role_in_use | 409 | You tried to delete a role that still has members. |
role_locked | 409 | You tried to change the Owner role. |
validation_failed | 422 | For example, an unknown permission key or a missing name. |
confirmation_required | 428 | A delete over the API without "confirm": true. |