Encadena SIF

Description

Encadena SIF is an independent plugin. Veri*factu (Verifactu) is the invoice verification system of the
Spanish Tax Agency (AEAT): this plugin is not affiliated with, endorsed by or sponsored by the AEAT.

Encadena SIF turns every WooCommerce order into a Spanish billing record (registro de facturación) that follows
Royal Decree 1007/2023 and Order HAC/1177/2024: it creates the record, chains it with its SHA-256 hash, prints the
tax QR and either sends it to the Spanish tax agency (VERIFACTU mode) or keeps it chained locally (non VERIFACTU
mode, with event records).

It is a Verifactu plugin: Verifactu is how everyone writes it, and Veri*factu is the official name the AEAT uses.
Both are the same regulation, and this plugin works either way: with a certificate it submits to the AEAT, and without
one it keeps the chain in the shop.

The plugin is free and complete: issuing, voiding, corrective invoices, QR, PDF and submission with the
shop’s own certificate. Every feature is in this download; nothing is held back.

What it does, and why it is built this way

  • The hash reproduces exactly the official AEAT examples (three cases from the technical specification v0.1.2),
    and the QR reproduces the four official URL variants.
  • Records are immutable: they are only inserted, never updated or deleted. The submission state lives in a
    separate table, so the fiscal content of a record never changes.
  • Independent chains per taxpayer and correlative numbering per series and tax ID.
  • The certificate is stored outside the public directory, encrypted, in uploads/encadena-sif-certs/, and its
    password is encrypted too: it is read from the ENCASI_CERT_PASS constant in wp-config.php when you define it, or
    from the encrypted copy the plugin keeps next to the certificate.
  • PDF invoice with the QR: with PDF Invoices & Packing Slips for WooCommerce active, the invoice carries the
    record number and date, the customer tax ID, the issuer’s fiscal data and the verification QR.
  • Compatible with WooCommerce High-Performance Order Storage (HPOS).

What the shop owner never has to fill in

The system identifier, its version, the producer and the responsible declaration travel with the plugin. The shop
only configures its own data: tax ID, legal name, series, when to invoice, and its certificate.

External services

The plugin connects to two external services. Both are optional: without a certificate it never contacts the AEAT,
and the Telegram notice stays off until a bot token and a chat are entered.

Spanish Tax Agency (AEAT) — Veri*factu

  • What is sent: the billing record (invoice number and date, amounts and tax breakdown, the customer’s tax ID and
    name, the previous record’s hash and the hash of the record itself). No other data of the shop or of the customer
    is sent, and nothing is sent while the plugin is in non VERI*FACTU mode.
  • When: only when the mode is VERI*FACTU and an order reaches the status you chose, and when you press
    “Test connection” in the panel.
  • Where: https://prewww1.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP (test) or
    https://www1.agenciatributaria.gob.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP (production).
  • How it identifies itself: with the certificate you upload (mutual TLS). There is no shared credential and no
    account with the AEAT.
  • Terms of service: https://sede.agenciatributaria.gob.es/Sede/condiciones-uso-sede-electronica/aviso-legal.html
  • Privacy policy: https://sede.agenciatributaria.gob.es/Sede/condiciones-uso-sede-electronica/aviso-legal/politica-privacidad.html

Telegram (optional notices)

  • What is sent: the text of the notice (invoice issued, submission rejected, summary) and the chat identifier
    you configure. No customer data beyond what the notice text already shows.
  • When: only if you enter a bot token and a chat ID in the settings, and only when one of those events happens.
  • Where: https://api.telegram.org/bot<token>/sendMessage, the official Telegram Bot API.
  • Terms of service: https://telegram.org/tos
  • Privacy policy: https://telegram.org/privacy

The plugin does not send telemetry, does not contact any update server of its own and does not share data with any
other third party.

Privacy

The plugin does not send telemetry and does not contact any server of its own. What leaves the site is what is
described in External services above: the billing record submitted to the AEAT when the shop runs in
VERI*FACTU mode with a certificate, and the optional Telegram notice, if it is switched on.

  • Privacy policy: https://farowp.com/privacidad
  • Terms of service: https://farowp.com/terminos

Screenshots

Installation

  1. Upload the plugin folder to /wp-content/plugins/, or install it from the zip.
  2. Go to Encadena SIF Issuer and enter the tax ID, the legal name and the series.
  3. In Certificate, add define('ENCASI_CERT_PASS', '…'); to wp-config.php and upload your .p12.
  4. In Invoicing, choose the mode, the environment (start with AEAT test) and when an order is invoiced.
  5. Place a test order and move it to the status that invoices: the record appears in Records.

The full guide ships inside the ZIP, in Spanish and English: guia/GUIA-DE-INSTALACION.pdf and guia/INSTALL-GUIDE.pdf. It covers the two modes, the two environments, the ten-minute check and what to do when something does not add up.

FAQ

Is this electronic invoicing (factura electrónica)?

No. This covers the billing record system (Veri*factu). Business-to-business electronic invoicing is a different
regulation (Law 18/2022 and Royal Decree 238/2026).

Do I need an AEAT “homologation”?

There is no such homologation. The manufacturer signs a responsible declaration (art. 15 RRSIF), which is
reproduced inside the plugin, in the Help tab.

What happens if I uninstall the plugin?

Settings are removed, billing records are not: the law requires keeping them.

Does it work without a certificate?

It issues and chains records but cannot submit them. The panel warns about it in the header and in the summary.

Does it send data anywhere else?

Only to the two services described in External services: the AEAT endpoint you select (test or production), and
only if you enable it, your own Telegram bot. Nothing else leaves the site.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“Encadena SIF” is open source software. The following people have contributed to this plugin.

Contributors

Translate “Encadena SIF” into your language.

Interested in development?

Browse the code, check out the SVN repository, or subscribe to the development log by RSS.

Changelog

1.4.18

  • Fix (plugin review): the migration of the old “vf_” prefix is skipped on a fresh installation, so the
    plugin no longer rewrites any post metadata it did not create. On sites coming from the old version the
    migration still runs, but only over orders and refunds.
  • The package for the directory does not ship its own update checker: WordPress.org serves those updates.

1.4.17

  • The links to the terms of service and the privacy policy of the Spanish Tax Agency in the “External services”
    section pointed to pages that no longer exist and returned 404; they now point to the current pages of the
    AEAT electronic office.
  • Added the privacy policy and the terms of service of the plugin itself.
  • Internal error messages are now in English, like the rest of the strings of the plugin.

1.4.16

  • Fix: in the chained-only mode (non VERI*FACTU) the overview counted every record as “waiting to be sent” and
    showed a red warning, because nothing is submitted in that mode by design. Pending submissions and submission
    errors are now counted only for installations that do submit.

1.4.15

  • Fix: the code fingerprint now leaves out the updater class. That file only exists in the package served from
    farowp.com, so the same version had two different fingerprints and the signed statement could only match one
    of the two packages. The fingerprint now identifies the invoicing code, which is the same in both.

1.4.14

  • Fix: the producer of the system is now identified as a natural person, with name and surname and tax ID,
    instead of with the trade name “Encadena”, which has no legal personality. The label of that field is
    “Name and surname” rather than “Company name”. The same identification goes to the AEAT in the
    SistemaInformatico block of every submission.
  • The trade names FaroWP and Encadena SIF stay as brand and commercial name of the system, not as producer.

1.4.13

  • Fix: the declaration of responsibility is no longer generated when it is downloaded. The package carries the
    PDF signed by the producer and the plugin serves that file. The date on the statement is the date it was
    signed, not the day it is opened. If a version has no signed statement yet, the plugin says so instead of
    building one.
  • Fix: the button to download the declaration returned HTTP 400, because its admin-post action was never
    registered.
  • Fix: the invoice PDF printed the issuer address twice, once from Encadena and once from the PDF plugin. The
    statement now prints only the tax ID and leaves the address to the document header.
  • Tweak: the label no longer asks the shop to sign and archive the statement: it states who signed it and when.

1.4.12

  • New: the panel has been redesigned. The overview shows four figures (records in the last seven days, waiting,
    with an incident and the last correct submission), the status of the certificate and the AEAT, a chart of the
    last eight weeks, the latest records and the state of the hash chain.
  • New: setup is now a four-step wizard inside Configuration (welcome, tax data, certificate, mode) that advances
    on its own and shows the result of every save. The separate “Getting started” screen and its menu entry are gone:
    there was only one setup, reached from two places.
  • New: the issuer address (address, postcode and town) is asked for in Issuer and printed on the PDF invoice. It
    was read by the invoice but there was no way to fill it in.
  • New: every tab shows “Settings saved” and the errors (an invalid tax ID, a missing company name) instead of
    saving silently.
  • Fix: opening the Plugins screen no longer fails when the update feed is read (a list was passed to wp_kses_post).
  • Fix: the Records tab printed a stray PHP closing tag above the table.
  • Fix: the certificate upload from the setup wizard continues to the next step instead of staying on the same one.

1.4.11

  • New: the Summary is the panel it should have been. Four figures at a glance: records issued in the last
    seven days (with the change against the previous week), those waiting to be sent, those with an error and
    when the last correct submission happened.
  • New: a system status card (certificate with days left, last answer from the AEAT and the environment in use),
    a bar chart of the last eight weeks with the incidents marked, and the latest records in a table with number,
    date, customer, type, submission status and total.
  • New: a side column with the hash chain (total records, verification and last hash), the setup checklist with
    its progress, and the guide and statement links, plus the versions in the footer.
  • The four-step guide and the rest of the tabs do not change.

1.4.10

  • Fix: the Plugins screen no longer breaks when the version feed is read. The published feed sends the
    changelog as a list, and the plugin information window passed it to WordPress as if it were text, which
    brought down the whole Plugins screen on sites that also have Encadena SIF Pro installed.
  • Fix: the “requires”, “tested” and “PHP” data are shown again in the version details window; the published
    feed names them differently and they were arriving empty.

1.4.9

  • New: getting-started wizard, in four steps, that opens by itself the first time the plugin is activated:
    tax details (with the check letter validated as you type), certificate, and how you invoice. It can be left
    halfway and picked up later, and it stays in the menu as “Getting started”.
  • New: a help note under every field of the wizard explaining what goes in it and what the AEAT does with it.
  • Fix: the issuer tax ID is now checked against its control letter before saving. A wrong one was accepted and
    every record was rejected later by the AEAT (error 1239), with the invoice already numbered.
  • Fix: a non-empty index.php left in the data folder by an earlier version is rewritten empty on upgrade, not
    only on a fresh install. The folder keeps its .htaccess with Require all denied.

1.4.8

  • Fix (plugin review): the data folder in uploads no longer writes a non-empty index.php. It was the last
    place doing it (includes/class-encasi-remision.php): the directory protection file is now created empty
    (0 bytes), which is the only form the guidelines allow. The folder keeps its .htaccess with Require all
    denied
    , so nothing inside can be listed or fetched.
  • Fix: the internal version constant ENCASI_VERSION was still 1.4.6, so the panel, the record header and the
    AEAT submission reported an older version than the release. It now follows the plugin version.

1.4.7

  • Fix (plugin review): the certificate folder no longer writes an index.php with content. It is created empty, which is the only form the directory allows; the folder keeps its .htaccess (deny) and an empty index.html, so the certificate stays unreachable from the browser.
  • Fix (plugin review): the two remaining defines without the plugin prefix, VFRUNTIME and VFRUNTIME_VERSION, are now ENCASI_RUNTIME and ENCASI_RUNTIME_VERSION. No behaviour changes: it is the same runtime marker, renamed as the review guidelines require.
  • Translations: Spanish, Catalan and Galician for the new changelog lines.

1.4.6

  • New: when the AEAT rejects a record, the reason now opens in a dialog on the order screen, with what happened and what to do, instead of being left only in the order notes at the bottom of the page. It opens by itself once per session; the “See what happened” button next to the status reopens it.
  • New: the most recent rejected record in the Records tab also opens its explanation by itself.
  • New: 3000 and 2007 added to the explanation dictionary, and 4104 corrected: it is “tax ID not identified”, not an expired certificate.
  • Translations: Spanish, Catalan and Galician for the new texts.

1.4.5

  • Fix: a 3000 “duplicate” answer from the AEAT is no longer shown as accepted. The AEAT answers EstadoEnvio “Incorrecto” when a different invoice already uses that number and date, so the invoice never entered; the panel used to say “accepted” and the QR led nowhere.
  • New: “Starting number” setting. When the counter restarts (fresh install, wiped data) the numbering began again at 1 and collided with the invoices the AEAT already had. Set the number to start above the last one used.
  • New: the error hint for 3000 and 2007 explains what to do (same invoice already declared, or change the series).

1.4.4

  • Every global identifier moved from the short “vf_” prefix to “encasi_” / “ENCASI_”, as required by the plugin directory guidelines. Existing settings, invoices, submission log and order metadata are migrated once on upgrade, so no data is lost.
  • The certificate folder is now resolved with wp_upload_dir() and lives in uploads/encadena-sif/certs; certificates saved in the previous locations are moved automatically.

1.4.3

  • New version notices: the plugin checks farowp.com twice a day and, when there is a newer release, it
    shows up in Plugins Updates and installs with the usual button. Until now a shop could keep the
    version it installed on day one for years, which in a billing program means issuing invoices with a
    system that no longer complies. Nothing is sent from your site: it is a plain read of a public file.
  • If the plugin is ever published on WordPress.org, this notice steps aside on its own and updates come
    from the official repository.

1.4.2

  • The declaration of responsibility (article 15 RRSIF) now arrives closed in the Help tab, behind a
    button that opens it in place: it does not reload the page and needs no JavaScript. The text, the PDF
    download and the missing-data warning are the same; only the initial state changes.

1.4.1

  • New Report a problem box in the Help tab: it shows the details needed to reproduce a failure
    (plugin, core, WordPress, WooCommerce and PHP versions, mode, environment and certificate state),
    with a button to copy them and another to write the report by email. It never sends anything on its own,
    and it carries no tax ID, no customer data and no certificate path.
  • The testers’ channel can be added to that box from a filter, without touching the plugin.

1.4.0

  • New name: the plugin is now Encadena SIF. Only the visible name, the slug and the text domain change; the settings, the billing records and the certificate stay where they were, so
    updating does not lose anything.
  • The name shown inside the plugin (menu, screens, schedule label and notices) is the same as in the directory.
  • The locale files are renamed to the new text domain.
  • Scripts are enqueued with wp_enqueue_script() / wp_add_inline_script(): no raw <script> tags are printed.
  • Every output is escaped (esc_html, esc_attr, esc_url, wp_kses_post).
  • All functions, options, constants and tables carry the plugin prefix.
  • Requests to the AEAT and to Telegram go through the WordPress HTTP API (wp_remote_post()); the client
    certificate is attached with the http_api_curl hook.
  • The certificate is stored in uploads/encadena-sif-certs/, not in wp-content/; the file of an older installation
    is moved there automatically on the first upload or on the first request.
  • The settings are sanitized with a callback of their own, and the certificate path is checked against the folder
    the plugin uses (realpath, no traversal).
  • Secrets on disk (certificate password, Telegram token, SMTP password) are encrypted with AES-256-GCM and a local
    key file. No external process is started in any system.
  • External services (AEAT and Telegram) are documented in the readme: what is sent, when, and their terms and
    privacy links.

1.3.2

  • First public release. The readme also spells it “Verifactu”, as most people write it, so the search finds it.

1.3.1

  • Initial submission. The interface is in English and fully translatable (456 strings); the Spanish
    translation is published on translate.wordpress.org.

1.2.0

  • Internal build. The plugin is free and complete.
  • Distribution and licence metadata prepared for the WordPress.org directory.

1.1.1

  • Complete responsible declaration: address, contact email, legal representative, place of signature and
    availability come from the producer and travel with the plugin.
  • The panel shows the whole document and warns about missing data.
  • The declaration can be downloaded as a PDF from the Help tab.

1.1.0

  • Step-by-step, collapsible guide in every panel tab.
  • Warning when the tax ID and the name do not match (the AEAT 4104 error).
  • Warning for a certificate saved on disk but not linked to the settings.
  • Red warning while in Production, so nobody declares by accident.

1.0.2

  • AEAT failures (SOAP <Fault>) are stored as rejections with their code and reason.
  • Added the hint for error 4104.

1.0.1

  • Fixed: the certificate was uploaded and encrypted but the panel kept saying “No certificate”.
  • Uploading a certificate removes the other extension (.p12 or .pfx).
  • The panel shows the certificate holder and tax ID without the full distinguished name.

1.0.0

  • Own tabbed panel (Summary, Issuer, Invoicing, Certificate, Records, Help) with status checks.
  • Every invoicing option explained on screen.
  • Producer data and the responsible declaration no longer asked from the shop.
  • PDF invoice with the tax QR and the verification texts.

0.1.0

  • First development version: record core (hash verified against the official AEAT examples), immutable store,
    settings, diagnostics panel and responsible declaration.