Scopes i irreversibilitat
Com llegir el scope requerit i la irreversibilitat de cada endpoint des de l'especificació OpenAPI — les extensions x-required-scope i x-irreversible — i el catàleg d'operacions irreversibles.
Cada endpoint públic declara dues peces de metadata de seguretat a
l'especificació OpenAPI: el scope exacte que enforça i si l'operació es pot
desfer. Els clients (el CLI, els agents, el teu propi tooling) les
llegeixen per fallar aviat — bloquejar una crida quan la key no té el scope,
confirmar abans d'una acció irreversible — en lloc de descobrir el problema per
un 403 o una mutació irrecuperable.
Llegir-ho des de l'especificació
Cada operació a l'especificació OpenAPI porta dues extensions personalitzades:
{
"operationId": "public-api.v1.invoices.delete",
"x-required-scope": "invoices:delete",
"x-irreversible": true
}x-required-scope— l'únic scoperesource:actionque l'API key ha de tenir per cridar l'operació. Present a totes les operacions llevat deGET /v1/me, que no necessita cap scope: qualsevol credencial vàlida es pot consultar a si mateixa.x-irreversible—truenomés a les operacions que no es poden desfer. Absent (tractat com afalse) a tota la resta.
Són extensions de proveïdor x-*, així que un visor OpenAPI genèric pot no
renderitzar-les — però qualsevol client que parsegi l'especificació (com el
CLI) les llegeix directament. Genera un client des de l'especificació i heretes
totes dues.
Scopes
Els scopes són resource:action (p. ex. invoices:read, contacts:delete) — el
mateix catàleg tancat que fan servir la REST API i les API keys. Una petició la
key de la qual no té el scope retorna 403 amb code: insufficient_scope.
Demana només els scopes que la teva integració necessita.
Una operació exigeix un segon scope a més de x-required-scope quan un camp
amplia el que llegeix: POST /v1/companies/{company}/purchase-invoices amb
source_purchase_invoice_id necessita també purchase_invoices:read, perquè
copia les línies d'un altre document. Consulta
Línies de compra mesurades.
Les operacions de control horari porten els seus propis scopes — employees:*,
time_entries:*, work_schedules:*, absences:*, presence:read,
holidays:read i payroll_exports:read — tots darrere el mòdul
control_horario. Consulta Control horari.
Les automatitzacions fan el mateix amb automations:read, automations:write,
automations:delete i automation_runs:read, darrere el mòdul automations.
Consulta Automatitzacions.
El model de comptes afegeix els seus propis scopes. account:read, account:write i
account:owner cobreixen el propi compte (les seves keys, el seu consum i la seva
titularitat), members:*, invitations:* i nif_transfers:* el seu equip i els
seus traspassos de NIF (necessiten el mòdul user_management), i companies:* la
seva cartera de NIF. Consulta Autenticació › Administració del compte.
Dos scopes són privilegiats: accounts:read i accounts:write. Permeten que un
compte aprovisioni, administri i cobri comptes gestionats per als seus clients, i
funcionen diferent de qualsevol altre scope: el super-scope * no els cobreix,
Factuarea concedeix el privilegi compte a compte i el comprova a cada petició
(403 privileged_scope_required si falla),
i el consentiment OAuth mai no els concedeix, així que fes servir una API key.
Consulta Scopes privilegiats i
Comptes gestionats.
Els documents de control (DeCA) fan servir transport_documents:read,
transport_documents:write (esborranys i enviament per email),
transport_documents:delete (només esborranys) i transport_documents:transition
(emetre, modificar, tancar, reobrir, anul·lar i substituir), darrere el mòdul
transport_documents, que al seu torn requereix delivery_notes. El PDF de cada
versió exigeix pdfs:read; el justificant d'emissió
(GET /v1/companies/{company}/transport-documents/{transport_document}/issuance-proof) no és un PDF del document sinó
l'exportació del seu registre d'emissió, així que exigeix transport_documents:read.
Consulta
Document de control (DeCA).
Els projectes i les tasques fan servir projects:read|write|delete,
tasks:read|write|delete, users:read i notifications:read|write.
projects:* i tasks:* són darrere el mòdul tasks en emetre la
credencial: una key amb aquests scopes per a una empresa sense el mòdul es
rebutja amb scope_not_allowed_by_plan, i sense el scope cada petició rep
insufficient_scope. users:read i notifications:* són transversals i no
pertanyen a cap mòdul. Els dos scopes d'esborrat són només d'API key: un
consentiment OAuth mai no els concedeix. Facturar les hores d'un projecte
(POST /v1/companies/{company}/projects/{project}/time-invoices) exigeix invoices:write, no un
scope de projectes, perquè crea una factura. Consulta
Projectes i tasques.
El catàleg complet — cada scope, què concedeix, i els sensibles — és a
Scopes i permisos. Un scope no sempre es deriva del nom del
recurs: alguns endpoints enforcen un scope diferent del que endevinaries (les
descàrregues de PDF enforcen pdfs:read, els mètodes de pagament enforcen
invoices:read, les transicions d'estat enforcen un scope :transition, les
accions de VeriFactu enforcen verifactu:*). Llegeix sempre x-required-scope
en lloc d'inferir-lo.
Una API key pot tenir el super-scope *, que satisfà qualsevol
x-required-scope llevat dels privilegiats accounts:read i
accounts:write. * no cobreix accounts:*: una key que només tingui *
respon 403 insufficient_scope en aquestes operacions, per àmplia que sembli.
Llista accounts:* de manera explícita, en un compte que tingui el privilegi.
Consulta el super-scope.
Operacions irreversibles
Una operació marcada x-irreversible: true no té desfer: esborra dades, emet
un registre fiscal, transiciona un document a un estat terminal, rota o revoca un
secret, o canvia qui és titular d'un compte, qui hi arriba o qui el paga. El
CLI demana una confirmació tipada abans
d'executar-ne una; el teu propi tooling hauria de protegir-les igual.
Aquestes són les categories que porten x-irreversible: true:
| Categoria | Exemples | Scope |
|---|---|---|
| Esborrats (individuals) | contacts.delete, invoices.delete, products.delete, purchase_invoices.delete, webhook_endpoints.delete… | <resource>:delete |
| Eliminacions de subrecursos de catàleg | products.presentations.delete, products.variants.delete, products.supplier-offers.delete, price-lists.delete, price-lists.items.delete, price-lists.items.purge_retired | products:write / price_lists:write |
| Esborrats massius | invoices.bulk_delete, contacts.bulk_delete, products.bulk_delete… | <resource>:delete |
| Esborrats de tasques i projectes | tasks.delete, tasks.bulk_delete, tasks.comments.delete, tasks.attachments.delete, tasks.time_entries.delete, task_labels.delete, projects.delete, projects.columns.delete, projects.custom_fields.delete: les nou operacions irreversibles del mòdul | tasks:delete / projects:delete |
| Emissió / numeració fiscal | invoices.send, invoices.mark_sent, invoices.assign_real_number, invoices.corrective, invoices.substitute_simplified | invoices:send / invoices:write |
| Void / anul·lació | invoices.void, invoices.annul | invoices:void |
| Conversions terminals | quotes.convert, proformas.convert, delivery_notes.convert | <resource>:transition |
| Cancel·lar / signar | delivery_notes.cancel, delivery_notes.sign, recurring_invoices.cancel, recurring_invoices.generate | <resource>:transition / :write |
| VeriFactu (AEAT) | invoices.verifactu_create, verifactu.records.subsanar, verifactu.settings.update, verifactu.certificates.revoke | verifactu:write |
| Secret / certificat | webhook_endpoints.rotate_secret, verifactu.certificates.revoke | webhooks:write / verifactu:write |
| Traspàs de NIF | account.nif_transfers.create, account.nif_transfers.accept, account.nif_transfers.revoke | nif_transfers:write |
| Titularitat i equip del compte | account.owner.transfer, account.members.delete | account:owner / members:write |
| Keys i webhooks del compte | account.api_keys.revoke, account.api_keys.rotate_secret, account.webhooks.delete, account.webhooks.rotate_secret | account:write / webhooks:delete / webhooks:write |
| Comptes gestionats (privilegiat) | managed_accounts.create, managed_accounts.claim_tokens.create, managed_accounts.management.end, managed_accounts.plan.update, managed_accounts.imports.create | accounts:write |
| Oblit GDPR | delivery_notes.signature_audits.forget | delivery_notes:gdpr_forget |
| Documents de control | transport_documents.issue, transport_documents.modify, transport_documents.cancel, transport_documents.supersede, transport_documents.send | transport_documents:transition / transport_documents:write |
| Enviament FacturaE (B2G) | invoices.face_submissions.submit, face_submissions.cancel | facturae:write |
| Segellat del tancament mensual | monthly_time_record_closes.seal | time_entries:write |
| Rellançament (reexecució) | automations.runs.replay, automations.runs.steps.replay, integrations.events.replay | automations:write / integration_events:write |
Treure d'una tasca una relació, un enllaç extern, un vincle amb una entitat o una
etiqueta no és irreversible —cadascun es pot tornar a crear— i només necessita
tasks:write.
Aquesta llista és el resum llegible. La font de veritat llegible per màquina
és x-irreversible a l'especificació — un client que la llegeix es manté
correcte encara que el catàleg creixi.
Ajuntant-ho tot
Un client segur fa dues comprovacions abans d'una mutació:
- Scope-check — té la key el
x-required-scope? Si no, atura't en local (sense gastar un round trip). El CLI surt amb4; consulta scope-check. Una operació sense l'extensió (GET /v1/me) no necessita comprovació, i per aaccounts:*el scope és necessari però no suficient: el compte també ha de tenir el privilegi, queGET /v1/meinforma aaccount.is_provideriaccount.privileged_scopes. - Confirmació d'irreversibilitat — és
x-irreversibletrue? Si ho és, confirma abans de cridar. El CLI requereix--confirm <id>; consulta operacions irreversibles.
Els SDKs oficials i el CLI fan totes dues per tu. Si generes el teu propi client des de l'especificació, cabla aquestes dues comprovacions tu mateix des de les extensions.
Permisos de botigues
La gestió de botigues fa servir stores:read i stores:write; els scopes del proveïdor són woocommerce_store:read, woocommerce_store:write, shopify_store:read i shopify_store:write. Les proves de connexió requereixen el scope d’escriptura del proveïdor. Aquests scopes s’assignen a API keys i queden fora del consentiment OAuth. Consulta la taula d’operacions de botigues.