Scopes & permissions
The OAuth consent scope catalog, how it maps to the fine-grained scopes tools enforce, the account and privileged scopes, the super-scope, and plan/module gating.
Every MCP tool declares the scope a credential must hold to call it. Scopes work slightly differently per channel:
- API keys are created directly with fine-grained scopes
(
resource:action, e.g.invoices:read) — the same closed catalog the REST API uses. You can also grant the super-scope*, which does not cover the two privileged scopes. - OAuth tokens are granted dotted scopes (
resource.action, e.g.invoices.read) on the consent screen. The server translates these to the fine-grained scopes automatically, so both channels enforce the same set at the tool boundary.
OAuth consent catalog
These are the scopes a user can grant a third-party app on the consent screen.
There are 79 simple scopes plus 3 macros. Consent grants the business data
of one tax ID and never the administration of the account: the keys, the team,
the ownership, the tax ID transfers, the tax ID portfolio and the accounts you
provision have no scope here and need an API key (see the
scopes without an OAuth scope). One of the 79, payroll_exports.write, is in the catalog but the screen does not
offer it, because no tool requires the scope it translates to.
What the screen grants by level and environment
The screen does not offer every scope in every case, and the confirmation checks it again on the server:
- View level. If you reach the company with View access, only read scopes can be granted: those ending in
.readand thefactuarea.readmacro. Confirming a write scope answers403 invalid_scopewithread_only_restricted_scopes, which lists the rejected scopes. - Test environment. The sandbox does not offer some modules: VeriFactu, the WhatsApp assistant, the document Vault, the Stripe, GoCardless, Monei, Slack and Teams integrations, webhooks and task integrations. Their scopes are not granted in Test; the confirmation answers
403withsandbox_restricted_scopes. - Expiry. The consent request expires 5 minutes after it opens, and the screen shows how many minutes are left.
Simple scopes
Each grants one capability. The Maps to column shows the fine-grained scope the tools enforce — the consent layer translates dotted OAuth scopes to these automatically. The Sensitive column marks scopes the consent screen flags and does not pre-check.
Profile
| Scope | Grants | Maps to | Sensitive |
|---|---|---|---|
profile.read | Read your name, email and active company. | account:read | no |
Contacts
| Scope | Grants | Maps to | Sensitive |
|---|---|---|---|
contacts.read | List and read canonical contacts. | contacts:read | no |
contacts.write | Create contacts and update identity, roles and profiles. | contacts:write | no |
contacts.delete | Archive contacts and remove unreferenced roles. | contacts:delete | yes |
Catalog — products, price lists, series, taxes
| Scope | Grants | Maps to | Sensitive |
|---|---|---|---|
products.read | List and read the product catalog. | products:read | no |
products.write | Create and update products. | products:write | no |
products.delete | Delete products. | products:delete | yes |
price_lists.read | Read price lists, items and effective prices. | price_lists:read | no |
price_lists.write | Create, update and delete price lists and items. | price_lists:write | no |
series.read | Read numbering series. | series:read | no |
series.write | Create and update numbering series. | series:write | no |
taxes.read | Read tax rates and retentions. | taxes:read | no |
taxes.write | Create and update tax rates. | taxes:write | no |
taxes.delete | Delete your own tax rates. | taxes:delete | yes |
Sales — invoices, quotes, pro-formas, delivery notes, transport control documents
| Scope | Grants | Maps to | Sensitive |
|---|---|---|---|
invoices.read | List and read invoices. | invoices:read | no |
invoices.write | Create and update invoices. | invoices:write | no |
invoices.send | Send invoices by email. | invoices:send | no |
invoices.delete | Delete draft invoices. | invoices:delete | yes |
invoices.annul | Annul issued invoices. | invoices:void | yes |
invoices.create_corrective | Issue corrective invoices. | invoices:write | no |
quotes.read | List and read quotes. | quotes:read | no |
quotes.write | Create and update quotes. | quotes:write | no |
quotes.send | Send quotes by email. | quotes:send | no |
quotes.delete | Delete quotes. | quotes:delete | yes |
quotes.convert_to_invoice | Accept/reject and convert quotes to invoices. | quotes:transition | no |
proformas.read | List and read pro-forma invoices. | proformas:read | no |
proformas.write | Create and update pro-formas. | proformas:write | no |
proformas.send | Send pro-formas by email. | proformas:send | no |
proformas.delete | Delete pro-formas. | proformas:delete | yes |
proformas.convert | Convert pro-formas to invoices. | proformas:transition | no |
delivery_notes.read | List and read delivery notes. | delivery_notes:read | no |
delivery_notes.write | Create, update and send delivery notes. | delivery_notes:write | no |
delivery_notes.send | Send delivery notes by email. | delivery_notes:write | no |
delivery_notes.delete | Delete delivery notes. | delivery_notes:delete | yes |
delivery_notes.convert | Convert delivery notes. | delivery_notes:transition | no |
delivery_notes.sign | Mark delivered / sign delivery notes. | delivery_notes:transition | yes |
transport_documents.read | List and read transport control documents (DeCA), their issuance evidence and QR code; also grants pdfs:read for the PDF of each version. | transport_documents:read | no |
transport_documents.write | Create and edit draft transport control documents and email them to the carrier. | transport_documents:write | no |
transport_documents.delete | Delete draft transport control documents. An issued one is never deleted. | transport_documents:delete | yes |
transport_documents.transition | Issue, modify, close, reopen, cancel and supersede transport control documents. Issuing, modifying, cancelling and superseding cannot be undone. | transport_documents:transition | yes |
PDF templates
The company's PDF template library: templates, brands (commercial identities), private assets and preferences. Both scopes require the pdf_templates plan module — see Plan & module gating — and cover the PDF templates tools. None of the factuarea.* macros includes them, so an app has to ask for them explicitly. preview_pdf_template also needs pdfs:read.
| Scope | Grants | Maps to | Sensitive |
|---|---|---|---|
pdf_templates.read | Read the PDF template library, its revisions, brands and the issuer's preferences. | pdf_templates:read | no |
pdf_templates.write | Manage PDF templates, revisions, brands, private assets and the issuer's preferences. | pdf_templates:write | no |
Purchases
| Scope | Grants | Maps to | Sensitive |
|---|---|---|---|
purchase_invoices.read | List and read expenses. | purchase_invoices:read | no |
purchase_invoices.write | Create and update expenses; duplicating from source_purchase_invoice_id also needs purchase_invoices:read. | purchase_invoices:write | no |
purchase_invoices.mark_paid | Mark expenses as paid. | purchase_invoices:transition | yes |
purchase_invoices.delete | Delete expenses. | purchase_invoices:delete | yes |
Payment scopes are asymmetric across sales and purchases. Registering a
payment on an invoice (register_invoice_payment) needs
invoices:write — it edits the invoice. Registering a payment on an
expense (register_purchase_invoice_payment) needs
purchase_invoices:transition instead, because on the buy side a payment moves
the expense through its lifecycle (pending → paid) rather than editing it.
Recurring invoices
| Scope | Grants | Maps to | Sensitive |
|---|---|---|---|
recurring.read | List and read recurring templates. | recurring_invoices:read | no |
recurring.write | Create and update recurring templates. | recurring_invoices:write | no |
recurring.pause | Pause recurring templates. | recurring_invoices:transition | no |
recurring.resume | Resume recurring templates. | recurring_invoices:transition | no |
recurring.generate_now | Emit a recurring invoice manually. | recurring_invoices:transition | yes |
recurring.delete | Delete recurring templates. | recurring_invoices:delete | yes |
Compliance and tax reports
| Scope | Grants | Maps to | Sensitive |
|---|---|---|---|
verifactu.read | Read VeriFactu records, events, certificates and config. | verifactu:read | no |
facturae.read | Download FacturaE XML and read FACe submissions. | facturae:read | no |
facturae.write | Submit invoices to FACe and request cancellations. | facturae:write | yes |
tax_reports.read | Read tax-report history, previews, files, stats and activity. | tax_reports:read | no |
tax_reports.write | Generate tax reports and review workbooks. | tax_reports:write | yes |
Webhooks
| Scope | Grants | Maps to | Sensitive |
|---|---|---|---|
webhooks.read | List webhook endpoints and deliveries. | webhooks:read | no |
webhooks.write | Create, update, rotate and ping webhook endpoints. | webhooks:write | yes |
webhooks.delete | Delete webhook endpoints. | webhooks:delete | yes |
These scopes cover the webhook endpoints of a tax ID. The webhook tools of the account reuse the same fine-grained scopes but consent never reaches them: see account tools that share a scope with a tax ID.
Workforce — control horario
Employee, time-tracking, absence, work-schedule, presence, holiday and
payroll-export data. Every workforce scope is sensitive (employee PII and
compliance data) and requires the control_horario plan module — see
Plan & module gating. Reads and employees.write are
grantable on the consent screen, payroll_exports.write is not offered, and the
privileged write and transition actions have no OAuth dotted scope and are
API-key-only (listed under the fine-grained scopes below).
| Scope | Grants | Maps to | Sensitive |
|---|---|---|---|
employees.read | List and read employees. | employees:read | yes |
employees.write | Create and update employees. | employees:write | yes |
time_entries.read | Read time-clock entries, balances and monthly time sheets. | time_entries:read | yes |
absences.read | List and read absences, policies and requests. | absences:read | yes |
work_schedules.read | Read work schedules and their assignments. | work_schedules:read | yes |
presence.read | Read live and daily presence. | presence:read | yes |
holidays.read | Read the company holiday calendar. | holidays:read | yes |
payroll_exports.read | Read generated payroll exports. | payroll_exports:read | yes |
payroll_exports.write | Not offered: payroll exports are read-only and no tool requires payroll_exports:write. | payroll_exports:write | yes |
Automations
Automation rules and their run history. Every automation scope is sensitive: a
rule can send emails and fire webhooks on the account owner's behalf, and the run
history carries the business payloads its actions moved (amounts, recipients,
outcomes). All three require the automations plan module — see
Plan & module gating. Reading and writing rules and reading
the run history are grantable on the consent screen; deleting a rule is not —
automations:delete has no OAuth dotted scope and is API-key-only (listed under the
fine-grained scopes below).
automations.read and automation_runs.read are granted separately on purpose. The
first one covers the rule book: the rules themselves, their sealed versions, the
trigger/action catalog and the dry run that reports what a rule would do without
doing it. The second one covers what the rules actually did: every run, its steps,
their typed discard reasons and the frozen trigger payload each run carries. An app
can read which automations exist without reading the business data every execution
touched.
| Scope | Grants | Maps to | Sensitive |
|---|---|---|---|
automations.read | List and read automation rules, their versions, the trigger/action catalog, the monthly quota and the dry run. | automations:read | yes |
automations.write | Create, update, activate and pause automation rules, and replay runs or single steps. | automations:write | yes |
automation_runs.read | Read the run history of your automations, its steps and their outcome. | automation_runs:read | yes |
Projects and tasks
Task projects, tasks and their surroundings. projects.* and tasks.* require the
tasks plan module — see Plan & module gating —, while
users.read and notifications.* are cross-cutting and belong to no module.
projects.write and tasks.write are sensitive: an app can create, move and
comment on tasks and log time on the account owner's behalf. users.read is
also sensitive: it exposes the whole directory of the company, emails included. Reading and
writing are grantable on the consent screen; deleting is not — projects:delete
and tasks:delete have no OAuth dotted scope and are API-key-only (listed under the
fine-grained scopes below).
| Scope | Grants | Maps to | Sensitive |
|---|---|---|---|
projects.read | List and read projects, their columns, custom fields, logged time and export. | projects:read | no |
projects.write | Create and update projects: columns, custom fields, archiving and task import. | projects:write | yes |
tasks.read | Search and read tasks, comments, activity, relations, links, attachments, logged time, labels and the agenda. | tasks:read | no |
tasks.write | Create and update tasks: status, assignment, comments, labels, attachments and time logged on your behalf. | tasks:write | yes |
users.read | Read the members of your company (name and email) to assign tasks, and your own user. | users:read | yes |
notifications.read | Read the notifications in your inbox. | notifications:read | no |
notifications.write | Mark the notifications in your inbox as read. | notifications:write | no |
Macro scopes
Convenience bundles that expand to a list of simple scopes at token-issue time. The token persists the expanded scopes — macros are never stored.
| Macro | Grants | Sensitive |
|---|---|---|
factuarea.read | Full read access to everything (no writes). | no |
factuarea.write | Read everything, plus create/update documents and send emails. | no |
factuarea.full | Read, write, send and destructive actions (delete, annul, mark paid, sign). Excludes VeriFactu writes. | yes |
The super-scope *
A credential holding * covers every scope except the two
privileged ones, accounts:read and accounts:write — all
668 tools of the catalog for an API key. It's the equivalent of an
owner key. Reserve it for one-off migrations or fully-trusted owner automations;
prefer the narrowest scope set for everything else. The super-scope is available to
API keys; OAuth consent grants explicit scopes (or macros), never a raw *.
A key that holds only * does not reach the ten
managed-account tools: they need accounts:read or
accounts:write listed on the key, and the account has to hold the privilege.
How OAuth scopes become fine scopes
When an OAuth token is issued, its dotted scopes are translated once to the fine-grained catalog the tools enforce. A few reconciliations are worth knowing:
recurring.*maps to therecurring_invoices:*resource.invoices.create_correctivemaps toinvoices:write(creating is a write).invoices.annulmaps toinvoices:void.- Lifecycle actions (
*.convert,*.sign,*.pause,*.resume,*.generate_now,*.mark_paid,quotes.convert_to_invoice) map to the resource's:transitionscope. - Any read scope on a document also grants the transversal read utilities
pdfs:read(download its PDF/receipt) andevents:read(its activity log). pdf_templates.readandpdf_templates.writemap topdf_templates:readandpdf_templates:write. They grant nopdfs:read: the PDF artifact tools get it from a document read scope, as in the previous bullet.verifactu.writeanddelivery_notes:gdpr_forgethave no OAuth dotted scope — they are unreachable via OAuth by design.- The scopes of the account —
account:write,account:owner,members:*,invitations:*,nif_transfers:*,companies:*and the privilegedaccounts:*— have none either.profile.readis the only account scope that consent translates, and it givesaccount:read.
Fine-grained scopes without an OAuth scope (API key only)
A few fine-grained scopes live in the closed resource:action catalog API keys
use, but have no dotted OAuth equivalent — they are never granted through a
third-party consent screen and are reachable only with an API key. Grant them on
the key directly (or via the super-scope *, except for accounts:*). Some are
gated by an integration module — the key's company must then hold the
corresponding plan (see Plan & module gating); the rest
are first-party scopes of the account.
| Scope | Grants | Module gate |
|---|---|---|
stripe_autoinvoicing:read | Read the Stripe Connect integration status, auto-invoicing config and connected accounts, and list auto-invoiced charges/correctives. | integration_stripe |
stripe_autoinvoicing:write | Toggle Stripe charge auto-invoicing, set the auto-issued series, and edit/disconnect connected accounts. | integration_stripe |
payouts:read | Read ingested Stripe payouts and their bank-reconciliation status. | integration_stripe |
These power the Payments & gateways tools.
A second group of API-key-only scopes governs what the account itself holds:
its keys, its team, its ownership and its tax ID transfers. account:read is the
only account scope that consent reaches, through profile.read. These are not
privileged, so the super-scope * does cover them. The members:*,
invitations:* and nif_transfers:* scopes need the user_management module: on
a plan without it they cannot be assigned to a key (see
Plan & module gating).
| Scope | Grants | Module gate |
|---|---|---|
account:write | Create, rotate and revoke the API keys of the account, change the tax IDs a key reaches and update the personalization of the account. | — |
account:owner | Transfer the ownership of the account to another person of the team. | — |
members:read | Read the members of the account, their grants on each tax ID and their module restrictions. | user_management |
members:write | Add, change the role of and remove members, set and revoke their grants on a tax ID — also one that another account grants to yours — and change their module restrictions. | user_management |
invitations:read | List and retrieve the invitations of the account. | user_management |
invitations:write | Send, resend and revoke invitations. | user_management |
nif_transfers:read | List the tax ID transfers that the account issued. | user_management |
nif_transfers:write | Issue, accept and revoke a tax ID transfer. | user_management |
How the grants of a member work on a tax ID of another account is in granted access.
A third group governs the tax ID portfolio of the account. Any account, on any
plan, lists and reads its own tax IDs, so companies:* has no module gate. What the
plan gates is adding a tax ID that the account pays for, and it does so inside the
operation, not in the scope: see additional tax IDs.
| Scope | Grants | Module gate |
|---|---|---|
companies:read | List and retrieve the tax IDs of the account, their statistics, creation status and issuing readiness, the charge preview of an additional tax ID and the consolidated workforce compliance overview. | — |
companies:write | Register, edit, activate and deactivate tax IDs of the account, and verify the creation of one. | — |
companies:delete | Archive a tax ID of the account. | — |
A fourth group covers workforce (control horario) write and transition
actions. Their read counterparts are OAuth-grantable (see the Workforce consent
scopes above), but these privileged scopes have no OAuth dotted equivalent — they
are API-key-only, the mirror of verifactu:write. All require the
control_horario plan module.
| Scope | Grants | Module gate |
|---|---|---|
employees:delete | Permanently delete employees. | control_horario |
time_entries:write | Clock in/out, record manual entries, manage time corrections and the monthly register close. | control_horario |
absences:write | Create and manage absence types, policies and requests. | control_horario |
absences:transition | Approve, reject and cancel absence requests. | control_horario |
work_schedules:write | Create, update, assign and archive work schedules. | control_horario |
A fifth group is the automation engine's delete scope. Its three siblings —
automations.read, automations.write and automation_runs.read — are
OAuth-grantable (see the Automations consent scopes above), but removing someone's
automation is destructive and cannot be undone through the API, so it stays out of
the consent catalog by design — the same call made for verifactu:write. It requires
the automations plan module.
| Scope | Grants | Module gate |
|---|---|---|
automations:delete | Delete automation rules. The deletion is logical and irreversible through the API: the rule stops firing, while its sealed versions and its run history stay auditable. | automations |
A fifth group is the task module's delete scopes. Their siblings — projects.read|write
and tasks.read|write — are OAuth-grantable (see the Projects and tasks consent scopes
above), but deleting a project or a task takes its comments, attachments and logged time
with it and cannot be undone through the API, so both stay out of the consent catalog by
design — the same call made for automations:delete. They require the tasks plan module.
| Scope | Grants | Module gate |
|---|---|---|
projects:delete | Permanently delete projects, board columns and custom field definitions. | tasks |
tasks:delete | Permanently delete tasks, comments, attachments, time entries and labels. | tasks |
verifactu:write and delivery_notes:gdpr_forget are also fine-grained,
API-key-only scopes
(covered above) — they enforce at the tool boundary just like any other scope,
but have no OAuth consent counterpart.
A final group covers the remaining first-party observability tools and the scopes that the closed catalog reserves, none of which has a dotted OAuth consent scope:
| Scope | Grants | Module gate |
|---|---|---|
api_keys:read | Reserved in the closed catalog; no published tool uses it. The API keys of the account are managed with account:read and account:write. | — |
api_keys:write | Reserved in the closed catalog; no published tool uses it. The API keys of the account are managed with account:read and account:write. | — |
api_keys:delete | Reserved in the closed catalog; no published tool uses it. The API keys of the account are managed with account:read and account:write. | — |
developers:read | Inspect the API request log of a tax ID and of the account. | — |
emails:read | Inspect sent-email history and status. | — |
integration_events:read | Inspect payment-gateway events and typed discard reasons. | integration_stripe |
integration_events:write | Replay parked payment-gateway events. | integration_stripe |
gocardless_autoinvoicing:read | Reserved in the closed catalog; no published tool currently uses it. | integration_gocardless |
gocardless_autoinvoicing:write | Reserved in the closed catalog; no published tool currently uses it. | integration_gocardless |
monei_autoinvoicing:read | Reserved in the closed catalog; no published tool currently uses it. | integration_monei |
monei_autoinvoicing:write | Reserved in the closed catalog; no published tool currently uses it. | integration_monei |
Privileged scopes
Two scopes are privileged: accounts:read and accounts:write. They let an
account provision, administer and charge the accounts of its clients, and the ten
managed-account tools need them. They differ from
every other scope:
- The super-scope
*does not cover them. List them on the key, next to*if you also want the rest of the account. - Factuarea grants them, account by account. You cannot assign them to yourself:
the API has no operation that grants the privilege, and creating a key that lists
them without it answers
403 privileged_scope_required.GET /v1/metells you whether your account holds it, inaccount.is_providerandaccount.privileged_scopes. - They are checked on every call. The key must list the scope, your account must
hold the privilege today and the person who issued the key must still be an owner
or an admin of the account. If any of the three fails the answer is
403 privileged_scope_required, and both causes answer alike. Nothing comes from a cache, so a revoked privilege stops the same key on its next call. - Consent never grants them and no module of the plan gates them: the gate is the privilege. They need an API key.
| Scope | Grants | Module gate |
|---|---|---|
accounts:read | List and retrieve the managed accounts of your account, read their provisioning usage and the preview of a plan change, and download the template of a bulk import. | — |
accounts:write | Provision a managed account, change its plan and its level, reissue its voucher, end its management, and preview and apply a bulk import. | — |
The bulk import needs the same scopes and has no MCP tool: see what the MCP server does not carry.
Account tools that share a scope with a tax ID
Ten tools administer the webhook endpoints of the account and two read its API
request logs. They reuse webhooks:read, webhooks:write, webhooks:delete and
developers:read, the scopes that the tools of a tax ID already use, so the scope
alone does not tell them apart. The channel does:
| Scope | Tools of the account | Channel |
|---|---|---|
webhooks:read | list_account_webhooks, get_account_webhook, list_account_webhook_deliveries, get_account_webhook_delivery | API key only |
webhooks:write | create_account_webhook, update_account_webhook, rotate_account_webhook_secret, test_account_webhook, retry_account_webhook_delivery | API key only |
webhooks:delete | delete_account_webhook | API key only |
developers:read | list_account_request_logs, get_account_request_log | API key only |
OAuth does not reach them even when it holds the scope: tools/list does not
announce them to an OAuth connection, and a direct call answers
403 forbidden_action. The webhook tools of a tax ID keep their consent scopes.
With an API key, each call checks first that the account of the credential is
reachable (404 account_not_found), then, for a tool that writes, that the key is
live (403 live_credential_required with a test key), and finally that the person
who issued the key is today an owner or an admin of the account and that the scope
of the key covers every real tax ID of the account (403 forbidden_action, the same
answer for both causes). The payer tier of the account also caps the endpoints: a
tier without account webhooks answers 402 addon_required, and a full one
422 account_webhook_endpoint_limit_reached.
Account webhooks describes each check.
Plan & module gating
Most published tools apply only a scope check — they're reachable as soon as
the credential holds the required scope. Several families are also module-gated.
The Price-list tools map price_lists:* to products.
The Payments & gateways tools map their scopes
(stripe_autoinvoicing:*, payouts:read, integration_events:*) to the
integration_stripe module.
The workforce tools (Employees, Employee seats, Work schedules, Time tracking,
Absences, Presence, Holidays) map their scopes (employees:*, time_entries:*,
absences:*, work_schedules:*, presence:read, holidays:read,
payroll_exports:*) to the control_horario module. The
Automations tools map their scopes (automations:*,
automation_runs:read) to the automations module. The team and transfer scopes
(members:*, invitations:*, nif_transfers:*) map to the user_management
module, which the empresario and enterprise plans include. The
Projects and Tasks tools map projects:* and tasks:* to the
tasks module, which every plan includes; users:read and notifications:* belong to
no module. The PDF templates tools map pdf_templates:* to the pdf_templates module, and the FacturaE (FACe) tools require the facturae module. When the company's plan
lacks the module, the server hides those tools from tools/list and returns
module_not_in_plan (-32005) on a direct call.
- Some scopes have no module gate, on purpose.
accounts:*are gated by the privilege of the account, not by the plan.companies:*let any account, on any plan, list and read its own tax IDs: the plan gates the purchase of an additional tax ID inside the operation (additional tax IDs), not the scope, so the tax ID portfolio does not depend on a plan module.account:*are operations of the account on itself and have none either. - Plan usage limits (e.g. monthly document quotas) are enforced at call time
and surface as
plan_limit_exceeded(-32004). See Errors & rate limits.
The whole public MCP surface also requires the company to have an active
Factuarea plan — API access is included in every plan; otherwise every call
returns addon_not_active (-32007).
Store permissions
Store management uses stores:read and stores:write; provider-specific scopes are woocommerce_store:read, woocommerce_store:write, shopify_store:read and shopify_store:write. Connection-test operations require the provider write scope. These scopes are assigned to API keys and are outside OAuth consent. See ecommerce stores for the operation matrix.