Authenticate Cadrumo with AEAT¶
Authenticate Cadrumo with Spain’s Tax Agency, the Agencia Estatal de
Administración Tributaria (AEAT), to let Cadrumo’s aeat command read information
your AEAT identity authorizes. Authentication provides read-only access only.
It never files a declaration, makes a payment, acknowledges a notification, or
performs representative-write actions.
Run aeat --help before continuing. If it fails, stop before configuring
authentication and follow the CLI troubleshooting guide.
If that does not restore the command, report the failure with the Cadrumo
version and redacted output.
When available to your identity, the command-line interface (CLI) can read filed declarations, expedientes, notifications, and filed justificantes. For Modelo 036/Censo profile facts, use the profile/Censo facts guide. Cadrumo no longer retrieves these facts live.
Before you start¶
You need:
an active profile.
aeat config auth configurerefuses withNo hay un perfil activountil you create one. Start the interactive wizard (a NIF, CIF, DNI, or NIE is a Spanish tax identifier); it prompts for the profile passphrase and offers an optional recovery code once the profile exists:1Start the interactive profile wizard, which prompts for the passphrase.aeat config profile create meaeat config profile create me2Confirm a profile is active before configuring AEAT authentication.aeat --format json config profile listaeat --format json config profile list{ "active_profile": "docs-sequence-sandbox", "command": "config.profile.list", "notices": [], "result": { "active_profile": "docs-sequence-sandbox", "profiles": [ { "active": true, "bucket_id": "<bucket-id>", "name": "docs-sequence-sandbox" } ] }, "schema_version": "2", "status": "success" }
Review interactive profile creation and confirm a profile is active.
the master-key passphrase that protects your local store; the tool prompts for it.
See supported providers¶
List providers:
aeat --format json config auth providersaeat --format json config auth providers{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.providers", "notices": [], "result": { "providers": [ { "description": "auth.catalogue.certificate_description", "id": "certificate", "label": "auth.catalogue.certificate_label" }, { "description": "auth.catalogue.clave_movil_description", "id": "clave_movil", "label": "auth.catalogue.clave_movil_label" }, { "description": "auth.catalogue.clave_permanente_description", "id": "clave_permanente", "label": "auth.catalogue.clave_permanente_label" } ] }, "schema_version": "2", "status": "success" }
Confirm the tool lists the supported authentication providers.
The list marks each provider as disponible (available now) or reservado (no disponible aún) (reserved, not available yet). Three are available:
certificate: your digital certificate file (certificado digital).clave_movil: mobile-based Cl@ve, confirmed on your phone.clave_permanente: Cl@ve Permanente, a DNI/NIE and password login.
Two more are listed but reserved, so you cannot configure them yet:
clave_pin: Cl@ve PIN, a one-time code system from AEAT. Reserved.dnie_pkcs: the national ID card (DNI electrónico). Reserved.
Configure one of the available providers.
Configure a provider¶
Configure the provider you use:
aeat config auth configure --provider certificate --file ./certificate.p12aeat config auth configure --provider certificate --file ./certificate.p12Use --file for providers that need a file, such as your digital certificate.
Keep credential files private and do not share them.
Check local readiness¶
Check what is configured:
aeat config auth statusaeat config auth statusAuthentication is not configured yet. provider configured False authenticated False available False active_profile docs-sequence-sandbox active_profile_status ready active_profile_registered True active_profile_record_present True backend_configured False backend_available False certificate_path health_severity health_summary
aeat --format json config auth testaeat --format json config auth test{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.test", "notices": [], "result": { "active_profile": "docs-sequence-sandbox", "active_profile_precondition_action": null, "active_profile_record_present": true, "active_profile_registered": true, "active_profile_status": "ready", "authenticated": false, "available": false, "backend_available": false, "backend_configured": false, "certificate_path": "", "configured": false, "health_severity": "", "health_summary": "", "persisted_session_expired": null, "persisted_session_present": false, "persisted_session_state": "no_provider", "probe_result": "no_provider", "probe_summary": "No auth provider is configured; nothing to probe locally.", "provider": "" }, "schema_version": "2", "status": "success" }
Confirm the tool reports what is configured and probes it locally.
If you want to inspect a specific provider, use --provider with either
command.
Renew your certificate before it expires¶
A digital certificate has an expiry date. The tool reads that date from the certificate file and warns you as it approaches. This helps you avoid a failed live read caused by an expired certificate.
Check the remaining validity:
aeat --format json config auth testaeat --format json config auth test{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.test", "notices": [], "result": { "active_profile": "docs-sequence-sandbox", "active_profile_precondition_action": null, "active_profile_record_present": true, "active_profile_registered": true, "active_profile_status": "ready", "authenticated": false, "available": false, "backend_available": false, "backend_configured": false, "certificate_path": "", "configured": false, "health_severity": "", "health_summary": "", "persisted_session_expired": null, "persisted_session_present": false, "persisted_session_state": "no_provider", "probe_result": "no_provider", "probe_summary": "No auth provider is configured; nothing to probe locally.", "provider": "" }, "schema_version": "2", "status": "success" }
Confirm the local probe reports the certificate's remaining validity.
The report tells you how the certificate stands:
More than 60 days left: the certificate is valid and reports the days remaining.
60 days or fewer left: a warning appears:
The certificate expires in N days. Plan the renewal.Start the renewal now.14 days or fewer left: the warning is critical. Renew before your next live read.
Already expired:
The certificate expired N days ago. Renew it before authenticating.A live read is refused until you replace it.
Renew the certificate with the body that issued it, such as the Fábrica
Nacional de Moneda y Timbre (FNMT) or AEAT. This happens outside the tool.
Download the renewed certificate file (.p12 or .pfx) to your machine.
Point the tool at the renewed file:
aeat config auth configure --provider certificate --file ./renewed-certificate.p12aeat config auth configure --provider certificate --file ./renewed-certificate.p12If the renewed certificate uses a new password, rotate the stored passphrase for its source:
aeat config auth certificate secret set --name personalaeat config auth certificate secret set --name personalConfirm the new expiry:
aeat --format json config auth testaeat --format json config auth test{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.test", "notices": [], "result": { "active_profile": "docs-sequence-sandbox", "active_profile_precondition_action": null, "active_profile_record_present": true, "active_profile_registered": true, "active_profile_status": "ready", "authenticated": false, "available": false, "backend_available": false, "backend_configured": false, "certificate_path": "", "configured": false, "health_severity": "", "health_summary": "", "persisted_session_expired": null, "persisted_session_present": false, "persisted_session_state": "no_provider", "probe_result": "no_provider", "probe_summary": "No auth provider is configured; nothing to probe locally.", "provider": "" }, "schema_version": "2", "status": "success" }
Confirm the local probe reports the renewed certificate's later expiry.
The report now shows the renewed certificate’s later expiry date.
Manage several certificates¶
If you act for several entities, register one certificate per entity. Do not
reconfigure aeat config auth configure --file every time you switch.
Register each certificate under a name:
aeat config auth certificate register --name personal --file ./personal.p12aeat config auth certificate register --name personal --file ./personal.p12aeat config auth certificate register --name apoderado-acme --file ./acme.p12 \
--friendly-name ACME SLaeat config auth certificate register --name apoderado-acme --file ./acme.p12 `
--friendly-name ACME SLList every registered certificate:
aeat --format json config auth certificate listaeat --format json config auth certificate list{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.certificate.list", "notices": [], "result": { "active_source": "", "sources": [] }, "schema_version": "2", "status": "success" }
Confirm the tool lists the registered certificates.
Select the one you want active:
aeat config auth certificate select --name apoderado-acmeaeat config auth certificate select --name apoderado-acmeRemove a registered certificate you no longer need:
aeat --format json config auth certificate remove --name personalaeat --format json config auth certificate remove --name personal{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.certificate.remove", "notices": [], "result": { "active": false, "certificate_path": "", "name": "personal", "removed": false }, "schema_version": "2", "status": "success" }
Confirm the tool removes a registered certificate by name.
Check every registered certificate’s expiry¶
Each registered certificate has its own expiry date. Check all registered certificates in one pass, not only the active one:
aeat --format json config auth certificate checkaeat --format json config auth certificate check{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.certificate.check", "notices": [], "result": { "entries": [], "has_warnings": false }, "schema_version": "2", "status": "success" }
Confirm the tool checks every registered certificate's expiry in one pass.
The report lists each registered certificate with its status:
ok: valid, with the days remaining.expiring: within the renewal window (60 days or fewer by default, or 14 days or fewer for the critical window). A warning names the certificate.expired: already expired. A warning names the certificate.
Renew an expiring or expired certificate with the body that issued it, then re-register it under its existing name:
aeat config auth certificate register --name apoderado-acme --file ./renewed-acme.p12aeat config auth certificate register --name apoderado-acme --file ./renewed-acme.p12Re-run aeat config auth certificate check to confirm the new expiry date.
Acquire or verify a live session¶
When you are ready to use a live-read command:
aeat config auth loginaeat config auth loginIf you need to intentionally reauthenticate, force a fresh authentication:
aeat config auth login --freshaeat config auth login --freshIf a previous login was interrupted and left the authentication step stuck, use
--reset-lock. Run it when login reports another login is in progress but it
is not.
End sessions or reset authentication¶
To end the local certificate-provider session without removing its configuration:
aeat --format json config auth logout --provider certificateaeat --format json config auth logout --provider certificate{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.logout", "notices": [], "result": { "bucket_id": "<bucket-id>", "cleared_session_state": false, "providers": [ "certificate" ], "removed_sessions": 0 }, "schema_version": "2", "status": "success" }
Confirm logout ends the local session while preserving the provider configuration.
To remove one provider’s local configuration, sessions, acquisition lock, registered certificates, and stored certificate secrets:
aeat --format json config auth reset --provider certificate --yesaeat --format json config auth reset --provider certificate --yes{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.reset", "notices": [], "result": { "bucket_id": "<bucket-id>", "cleared_locks": 0, "cleared_provider_configuration": true, "providers": [ "certificate" ], "removed_certificate_secrets": 0, "removed_certificate_sources": 0, "removed_sessions": 0 }, "schema_version": "2", "status": "success" }
Confirm reset removes the selected provider's local authentication state.
To remove local authentication state for every configured provider:
aeat --format json config auth reset --all --yesaeat --format json config auth reset --all --yes{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.reset", "notices": [], "result": { "bucket_id": "<bucket-id>", "cleared_locks": 0, "cleared_provider_configuration": true, "providers": [ "certificate", "clave_movil", "clave_permanente" ], "removed_certificate_secrets": 0, "removed_certificate_sources": 0, "removed_sessions": 0 }, "schema_version": "2", "status": "success" }
Confirm reset removes local authentication state for all configured providers.
Act for someone else (apoderado)¶
If you act as an authorized tax representative for another taxpayer, record locally who you represent and the relevant AEAT apoderamiento scopes. An apoderado is an authorized representative, such as a gestor or asesor.
The apoderamiento itself is granted at AEAT. The represented party authorizes you through AEAT’s own apoderamiento procedures. The commands in this section record that grant in your local profile so read commands know whose data they read. They never register, extend, revoke, or renounce an apoderamiento at AEAT. No command writes representation state to AEAT.
See the accepted scopes¶
List the scope codes the tool accepts:
aeat --format json config auth apoderado scopes listaeat --format json config auth apoderado scopes list{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.apoderado.scopes.list", "notices": [], "result": { "catalogue_version": "2026.05.bootstrap", "scopes": [ { "code": "CENSO", "modelo_codes": [ "036", "037" ], "name_en": "Censo declarations (registration, modification, deregistration)", "name_es": "Censo (modelo 036, 037)" }, { "code": "EXPED", "modelo_codes": [], "name_en": "Filing records and queries", "name_es": "Expedientes y consultas" }, { "code": "GENERALNT", "modelo_codes": [], "name_en": "General tax procedures", "name_es": "Trámites tributarios (general)" }, { "code": "INFORM", "modelo_codes": [ "347", "349", "720" ], "name_en": "Informational declarations", "name_es": "Declaraciones informativas (modelo 347, 349, 720)" }, { "code": "IVA", "modelo_codes": [ "303", "390" ], "name_en": "IVA periodic and annual returns", "name_es": "IVA (modelo 303, 390)" }, { "code": "NOTIFIC", "modelo_codes": [], "name_en": "Electronic notifications (DEHú)", "name_es": "Notificaciones electrónicas DEHú" }, { "code": "PAGOSF", "modelo_codes": [ "130", "131" ], "name_en": "Quarterly self-employed instalments", "name_es": "Pagos fraccionados (modelo 130, 131)" }, { "code": "RENT", "modelo_codes": [ "100", "714" ], "name_en": "Income tax and wealth declaration", "name_es": "Renta y patrimonio (modelo 100, 714)" }, { "code": "RETEN", "modelo_codes": [ "111", "115", "123", "180", "190", "193" ], "name_en": "Withholding tax declarations", "name_es": "Retenciones (modelo 111, 115, 123, 180, 190, 193)" } ] }, "schema_version": "2", "status": "success" }
Confirm the tool lists the accepted apoderamiento scope codes.
Each scope is an AEAT apoderamiento area. Examples include:
RENTfor modelos 100 and 714.IVAfor modelos 303 and 390.PAGOSFfor modelos 130 and 131.RETENfor withholding modelos.GENERALNT,CENSO,INFORM,NOTIFIC, andEXPEDfor their respective authority areas.
Record who you represent¶
Set the represented party’s tax identifier (NIF, CIF, DNI, NIE, or NII) and the scopes that match the grant at AEAT:
aeat --format json config auth apoderado configure --represented-nif 11111111H --scope \
IVA --scope PAGOSFaeat --format json config auth apoderado configure --represented-nif 11111111H --scope `
IVA --scope PAGOSF{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.apoderado.configure", "notices": [], "result": { "bucket_id": "<bucket-id>", "catalogue_version": "2026.05.bootstrap", "configured_at": "2026-04-01T09:00:00+00:00", "granted_scopes": [ "IVA", "PAGOSF" ], "notes": "", "represented_nif": "sha256:33982da1" }, "schema_version": "2", "status": "success" }
Confirm the tool records the represented party and scopes locally.
Repeat --scope for each code. The CLI rejects a comma-separated list. Scope
codes are uppercase. Use --scope ALL to record every catalogue scope at
once. The CLI rejects unknown codes and lists the accepted codes.
The active profile holds at most one apoderado configuration; configuring again replaces it. The represented identifier is stored encrypted.
Review or retire the configuration¶
Show what is recorded for the active profile:
aeat --format json config auth apoderado statusaeat --format json config auth apoderado status{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.apoderado.status", "notices": [], "result": { "bucket_id": "<bucket-id>", "catalogue_version": "2026.05.bootstrap", "configured": true, "configured_at": "2026-04-01T09:00:00+00:00", "granted_scopes": [ "IVA", "PAGOSF" ], "represented_nif": "sha256:33982da1" }, "schema_version": "2", "status": "success" }
Confirm the tool shows the apoderado configuration recorded locally.
aeat config auth apoderado check is the live-verification verb, but the
live AEAT read path is sealed. It refuses with a “live verification unavailable”
message and points you back to status. Use aeat config auth apoderado status
for the offline configuration read.
Remove the configuration when the representation ends:
aeat --format json config auth apoderado clearaeat --format json config auth apoderado clear{ "active_profile": "docs-sequence-sandbox", "command": "config.auth.apoderado.clear", "notices": [], "result": { "bucket_id": "<bucket-id>", "cleared": true }, "schema_version": "2", "status": "success" }
Confirm the tool removes the local apoderado record.
Clearing removes only the local record. The apoderamiento at AEAT is unaffected. Revoke it through AEAT’s own procedures.
Next steps¶
Run aeat config auth test before each live-read task. Follow Renew your
certificate before it expires when
the command reports an expiry warning.