eInvoice Validator for Mustang – Manual
1 · Overview
The eInvoice Validator for Mustang is a WordPress plugin. It provides a drop zone on a page of your site on which a visitor drops an e-invoice. The invoice is checked by the Mustangproject validator that you have put on your server yourself. The validation report then appears on the page and can be downloaded as a file.
The plugin is meant for operators of a WordPress site who want to offer invoice checking on their own server: for customers, for suppliers or for their own colleagues.
Caution: The plugin contains no validator and does not download one either. It starts the file Mustang-CLI.jar that lies at the path you set. It is an independent tool by invoicePress and not a product of the Mustangproject.
What the plugin does
- With a shortcode it puts a drop zone for e-invoices on a page or in a post.
- It accepts ZUGFeRD and Factur-X PDF as well as CII and UBL XML, by drag and drop or through file selection.
- For a PDF it reads the embedded invoice already in the browser and sends only this XML to your server.
- For every check it starts the Mustang validator on your server and shows its report in a plain-language view with rule texts and technical terms.
- It attaches the uploaded invoice to the report, so the findings stand in their place in the document view.
- It offers the validator's unchanged report as
report.xmlfor download. - It limits the number of checks per visitor and calendar day, and the file size.
- On the settings page it checks whether the validator is ready to start, and with a checksum it watches whether the jar file is still the one you agreed to.
- It gives an invoice opened in the eInvoice Viewer the button Validate with Mustang.
- It ships translations for German and French; the source texts are English.
What the plugin does not do
- It checks nothing without the Mustang validator and without Java on the server.
- For a PDF it checks only the embedded invoice. The PDF file itself does not reach the server and is therefore not examined.
- It does not read an ordinary or scanned PDF; a PDF without an embedded invoice is rejected with a message.
- It stores neither invoices nor reports and keeps no list of earlier checks.
- It addresses the validator in only one way: as a Java process on the same server. It cannot address a remote validation service.
Requirements
| What | Requirement |
|---|---|
| WordPress | from version 6.0 |
| PHP | from version 8.2 |
| Java | a Java runtime from version 11, installed on the server and callable for the web server user |
| Mustang validator | the file Mustang-CLI.jar, downloaded by you from the Mustangproject website and put on the server |
| Server | PHP must be allowed to start a Java program; the web server user must be able to read the jar file |
| Visitor's browser | JavaScript enabled |
screenshots/vm-ablage.en.pngThe drop zone on a WordPress page with the prompt to drag in an e-invoice or choose a file, below it the line with the formats accepted2 · Installation
Uploading the ZIP file
Distribution through wordpress.org
Distribution through the wordpress.org plugin directory is planned, but the plugin has not been published there yet. Once it is there, you find it through the search under "Plugins" and "Add New Plugin".
Providing the validator
These steps are part of the installation, because without them the plugin checks nothing.
Reaching the validator through a validation service
If your web space may not run Java or start programs, the plugin checks through a validation service. A validation service is one of two kinds of service that offer the same addresses:
- Validator Bridge: a small free service that runs Mustang on this or another computer and offers it over HTTP. Its manual comes with it.
- eInvoice API: a WordPress website with the plugin eInvoice API, which passes the check on to its own bridge and grants a key and a quota for it.
Path, Java binary and the integrity of the jar then concern the validation service and no longer this plugin.
Updating
You replace the plugin with the new version by uploading the new ZIP file. As long as the plugin is not on wordpress.org, WordPress does not announce a new version by itself. Your settings are kept. The plugin does not update the validator's jar file; you do that yourself (see chapter 6).
Removing
You deactivate and delete the plugin under "Plugins". The jar file and Java stay on the server, because neither belongs to the plugin. In the database the plugin creates the settings spmv_jar_path, spmv_java_bin, spmv_timeout_seconds, spmv_role_limits ( the table per role; until it is saved for the first time, the earlier single value spmv_daily_limit applies ), spmv_max_filesize_mb, spmv_trust_proxy and spmv_jar_sha256, plus the daily limit counters. The plugin does not clean up on deletion: the settings stay in the database. The counters expire by themselves after one day.
3 · First steps
screenshots/vm-systempruefung.en.pngThe section "Systemcheck" of the settings page with green ticks in all rows and the message that the validator can be startedscreenshots/vm-shortcode.en.pngThe WordPress editor with a page containing only the shortcode in square bracketsscreenshots/vm-bericht.en.pngThe page after a check: the drop zone at the top, below it the validation report with findings in plain language and the download button4 · Working with the validator
Dropping an invoice
The visitor drags a file onto the drop zone, or clicks it and chooses a file. The zone can also be operated with the keyboard: Enter or Space opens the file selection. Files ending in .pdf or .xml are accepted. While the validator runs, the zone accepts no second file.
Having a PDF checked
A ZUGFeRD or Factur-X PDF carries the invoice inside it as an XML attachment. The plugin reads this attachment in the visitor's browser; meanwhile the message says that the invoice is being read from the PDF. Only the XML goes to the server. The scripts needed for this are only loaded when a PDF is actually dropped. If the PDF contains no invoice, the message says so explicitly.
Waiting for the report
Java starts afresh for every check. The first seconds are therefore start-up and not checking. For an ordinary invoice about two seconds in total were measured with Mustang-CLI 2.25.0. While the check runs, a note stands below the drop zone.
Reading the report
The report appears below the drop zone. The plugin shows it in a plain-language view: the validator's findings stand there with rule texts and technical terms, and the uploaded invoice is attached as the document, so every finding stands in its place in the document. If this view cannot be built, the plugin shows a simpler report view; the report stays readable in any case. The display is shielded from your theme's styling.
Downloading the report
Above the report is the button "Download report.xml", next to it the row "Validation report". The button saves the report exactly as the Mustang validator output it. The file name is made of the invoice's name and the suffix -report.xml, for example invoice-4711-report.xml.
screenshots/vm-download.en.pngThe report header with the label "Validation report" and the button "Download report.xml"Seeing the daily limit
Below the drop zone stands "Remaining uploads today: …" with the number of checks the visitor has left that day. The number falls after every check that delivered a report. A rejected file does not count. When the limit is reached, the visitor gets the message "You have reached the daily upload limit. Please try again tomorrow."
Watching the validator
The section "Systemcheck" of the settings page is computed anew every time the page loads and never cached. It has three rows: "PHP can start external processes ( proc_open )", "A Java runtime is reachable" and "Mustang-CLI.jar is where the settings say". Every row carries a green tick or a red cross, and with a cross the next step stands below it. The button "Test the validator" sums up the result in one line and, where applicable, names the checks still open.
Securing the jar file
Mustang-CLI.jar is executable third-party code on your server. The section "Integrity of the jar" therefore shows two SHA-256 checksums: under "Accepted" the file you agreed to, and under "On disk" the file that now lies at the path. With "Accept the file on disk" you take over the existing file. If both values later differ, checking stays blocked until you accept the file again or put back the earlier one. "Forget accepted hash" deletes the remembered checksum; afterwards any jar file lying at the path is started.
screenshots/vm-jar-integritaet.en.pngThe section "Integrity of the jar" with the two checksums "Accepted" and "On disk" and the two buttons below them5 · Settings
You find the settings page under "Settings" and "E-Invoice Validator Mustang". You need the right to manage options for it.
screenshots/vm-einstellungen.en.pngThe settings page with the section "Mustang validator": path to the jar file, Java binary, timeout, daily limit, file size, proxy header and design kitSection "Mustang validator"
| Setting | Default | Effect |
|---|---|---|
| Way to the validator | local installation | "Local installation: Java on this server" starts Mustang-CLI.jar on the web server. "Validation service ( Validator Bridge or eInvoice API )" sends the invoice to the validation service at the address below. |
| Address of the validation service | empty | Only with the validation service. For a bridge the address it prints at its start, for example http://127.0.0.1:8090. For the eInvoice API of a website its REST address, for example https://example.com/wp-json/einvoice-api/v1. |
| API key of the validation service | empty | For a bridge on a server one of the keys in api.keys of its settings file. For the eInvoice API your API key of that website. A bridge on the same computer needs none. |
| Path to Mustang-CLI.jar | empty | The full path to the jar file including the file name, for example C:\mustangproject\Mustang-CLI-2.25.0.jar. Above the field it says whether a file was found at the path and how large it is. |
| Java binary | empty | If the field stays empty, java from the web server user's search path is used. This search path is often different from that of your own command line. If the systemcheck does not find Java, enter the full path here. |
| Timeout ( seconds ) | 60 | The longest time a check may take. The input field requires at least 5. |
| Daily uploads per role | every role 10 | A table with one row for guests ( not logged in ) and one row for each role of the site. Per row: empty means unlimited, 0 means no access, a number means that many checks per calendar day. Logged-in users are counted by user, guests by IP address. A user with several roles gets the most generous value. Administrators are never limited. Until the table is saved for the first time, the previous single value applies to every role. |
| Maximum file size ( MB ) | 8 | The largest file accepted. The smaller of this setting and the server's upload limit applies. |
| Trust proxy header | off | Uses the header X-Forwarded-For as the visitor's address. Only switch it on behind a trusted reverse proxy. |
| Design kit | Kit H | The look of drop zone and report. The two bundled kits A and H are available. The choice applies to all eInvoice tools on this site, not only to this plugin. |
Section "Systemcheck"
| Element | Default | Effect |
|---|---|---|
| Table of checks | – | Shows a tick or a cross per check, with a cross along with the next step. Computed anew every time the page loads. |
| Button "Test the validator" | – | Reports "Ready — the validator can be started." or "Not ready:" with the list of checks still open. |
Section "Integrity of the jar"
| Element | Default | Effect |
|---|---|---|
| Accepted | "nothing accepted yet" | The SHA-256 checksum of the file you agreed to. It is not typed but only taken over by button. |
| On disk | – | The checksum of the file that now lies at the configured path. |
| Button "Accept the file on disk" | – | Computes the checksum of the existing file and remembers it. Meanwhile "Hashing the file …" stands there; with a large file this takes noticeably long. Reload the page afterwards. |
| Button "Forget accepted hash" | – | Deletes the remembered checksum. Afterwards any file at the path is started. |
Shortcode
| Shortcode | Attributes | Effect |
|---|---|---|
[spmv_mustang_validator] | none | Puts the drop zone with message line and report area in this place. |
[spmv_mustang_validator]The shortcode has no attributes. Everything adjustable is on the settings page and applies to every place where the shortcode stands.
6 · Special cases
The invoice names a newer edition than the one Mustang knows. When an invoice names XRechnung 4.0 or the standard EN 16931-1:2026 in BT-24, Mustang checks it with the rules of the older edition it knows and may call it valid. A yellow note above the report then says that Mustang does not know this edition yet and that its result applies only to the older edition. The note changes nothing in the report itself.
You want to bring the Mustang validator to a new version. Put the new jar file on the server. If it has a different file name, enter the new path and save. The checksums now differ and checking is blocked. Click "Accept the file on disk", and it runs again.
You want to offer the check only to a closed circle. Put the shortcode on a page you protect with WordPress means, for example with a password or as a private page. Logged-in users are counted by user for the daily limit.
You want to check internally without a daily limit. In "Daily uploads per role", empty the rows of the roles that should check. Only do this on a site that is not publicly reachable, because every check starts a Java process on your server.
Your site stands behind a reverse proxy. Then WordPress sees the proxy's address as the visitors' address. Switch on "Trust proxy header" so the daily limit counts per visitor. Leave the switch off if no trusted proxy stands in front, because otherwise the visitor can set the header themselves.
The shortcode stands not in the page content but in a template or widget. The plugin loads its files as soon as the shortcode is output. If you want to load the files earlier on particular pages, there is the filter spmv_force_enqueue for that (see chapter 10).
Java is not found although it is installed. The web server runs under a user of its own with a search path of its own. Enter the full path to the Java program under "Java binary".
7 · Working with other packages
The plugin is self-contained. It needs no other invoicePress package, and the plain-language report view is built in.
| Package | What applies in the cooperation |
|---|---|
| Mustangproject's Mustang-CLI | Required. The plugin starts this file; it has its own licence and its own release cycle. |
| eInvoice Validator for KoSIT | Both plugins may run on the same site. Each keeps its own daily limit; checks in one use up nothing in the other. |
| Other invoicePress eInvoice tools | The setting "Design kit" applies jointly to all. Whoever changes it here changes it for all. |
| eInvoice Viewer from 2.35.0 | An invoice opened in the viewer gets the button Validate with Mustang. The report then appears in the viewer, and the check counts against the same daily limit as on the page with the shortcode. On the viewer's settings page, "Add-ons available from role" decides who sees the button. |
8 · Troubleshooting
| Sign | Cause | Remedy |
|---|---|---|
| Settings page: "Not configured yet." | No path to the jar file is entered. | Enter the full path to Mustang-CLI.jar and save. |
| Settings page: "There is no file at that path." | There is no file at the path, or the web server may not read it. | Check the spelling; on Linux upper and lower case matter. Set read permission for the web server user. |
| The systemcheck shows a red cross | A requirement is missing, for example Java is not found. | Follow the note below the row. For Java, enter the full path under "Java binary". |
| "The two differ. Validation stays blocked until you accept the file on disk — or until you put back the one you accepted." | The jar file at the path is no longer the accepted one. | Clarify why the file has changed. Then click "Accept the file on disk" or put back the earlier file. |
| The button reports "There is no readable file at the configured path." | On accepting, no readable file was found at the path. | Check path and read permission. |
| Visitor: "Please choose a PDF or XML file." | The file has an extension other than .pdf or .xml. | Choose a PDF or XML file. |
| Visitor: "The file is too large." | The file exceeds the configured size or the server's upload limit. | Raise "Maximum file size ( MB )"; if that is not enough, the server's upload limit. |
| Visitor: "This PDF carries no e-invoice. …" | The PDF has no invoice as an XML attachment, for example it was only printed or scanned. | Use a ZUGFeRD or Factur-X PDF or the XML file. |
| Visitor: "You have reached the daily upload limit. Please try again tomorrow." | The daily limit is reached. | Check again the next day or raise the role's number in "Daily uploads per role". |
| "This tool is not available for your account." | The visitor's role has a 0 in "Daily uploads per role". | As the operator, enter a number for this role or empty the field. |
| Visitor: "Security check failed. Please reload the page." | The request's security token has expired or is invalid. | Reload the page and drop the file again. |
| Visitor: "The file is empty." or "The file could not be read." | The file has no content or could not be read on the server. | Check the file and drop it again. |
| Visitor: "Please choose an XML file." | Something that is not XML reached the server. | Check the file; an XML file must really contain XML. |
| Visitor: "The upload failed. Please try again." | The transfer failed or the server did not answer usefully. | Try again. If it persists, look at the systemcheck and the server's error log. |
| "The validator took too long and was stopped." | The check exceeded the time limit. | On a slow server raise "Timeout ( seconds )". |
| "The validator could not be started. Check the java binary and the validator path in the settings." | Java or the jar file could not be started. | Look at the systemcheck; check "Java binary" and "Path to Mustang-CLI.jar". |
| "The Mustang validator is not configured. …" | No path is entered. | Enter the path on the settings page. |
[spmv_mustang_validator] stands on the page as text | The plugin is not active. | Activate the plugin under "Plugins". |
screenshots/vm-meldung-pdf.en.pngThe drop zone with the red message that the dropped PDF contains no e-invoice9 · Privacy and security
What stays in the browser. A dropped PDF does not leave the visitor's browser. The plugin extracts the embedded XML there, and only this is sent. The report for download is created in the browser from the server's answer.
What goes to the server. The invoice's XML goes to your own WordPress site, that is to your server. With the local installation the plugin starts the Mustang validator there as a Java program; what the Mustangproject's jar file does in turn lies outside the plugin. With the validation service the plugin sends the invoice to the address you have entered, and nowhere else. With your own Validator Bridge it stays in your network. With the eInvoice API of another website it goes to that website's operator, and his privacy policy and terms of use apply.
What is stored. For the check the invoice is copied into a working directory of its own, which is deleted again after the run; the WordPress upload folder is not touched. Invoice and report are not kept. Stored are the settings, the remembered checksum of the jar file and the daily limit counters. For anonymous visitors the IP address is used only as a hash value, for logged-in users the user account counts.
How the plugin protects the server.
- The server accepts only XML and reads no PDF.
- Every check requires a fresh security token, which the page fetches separately; this also works with cached pages.
- File size and daily limit restrict how often and with what the Java process is started.
- The checksum blocks checking as soon as the jar file no longer matches the accepted one.
- The buttons on the settings page are only open to logged-in administrators.
- The report is displayed in a shielded area of the page.
10 · For developers
| Kind | Name | Meaning |
|---|---|---|
| Constant | SPMV_VERSION | Version of the plugin; also the version tag on all scripts and stylesheets. |
| Constants | SPMV_FILE, SPMV_DIR, SPMV_URL | Main file, directory and URL of the plugin. |
| Constant | SPMV_SHORTCODE | Name of the shortcode: spmv_mustang_validator. |
| Filter | spmv_force_enqueue | Receives true or false and decides whether scripts and stylesheets are already loaded when the page is built. Default: true if the content of a single page contains the shortcode. |
| REST route | POST /wp-json/einvoice/v1/validate-mustang | Accepts an XML file in the field file; requires a valid security token in the header X-WP-Nonce, which a program fetches first with a POST to admin-ajax.php and action=einvoice_nonce. Answer with html, view, cssUrl, xml, filename, remaining. Errors with message and status 400, 413, 415, 422 or 429. |
| AJAX action | spmv_nonce | Returns a fresh security token for spmv_validate; also for anonymous visitors. |
| AJAX action | spmv_validate | Checks the file in the field file; also for anonymous visitors; status 403 for an invalid token. The viewer's button uses the same two actions. |
| AJAX actions | spmv_jar_reload, spmv_jar_forget_pin, spmv_test_connection | Buttons of the settings page; only with the right manage_options. |
| Static methods | SPMV_Plugin::bridge_texts(), SPMV_Plugin::instance()->enqueue_bridge_script() | Label, running message and error message of the viewer's button, and the report script on the viewer's page. The viewer only shows the button when both exist. |
| JavaScript | window.SPMV_renderReport( container, data ) | Shows a check result in an element; for reuse by other scripts. |
| JavaScript | window.EInvoice.register( 'validator', … ) | Registers the same function as renderReport in the shared registry. |
| Options | spmv_jar_path, spmv_java_bin, spmv_timeout_seconds, spmv_role_limits ( the table per role; until it is saved for the first time, the earlier single value spmv_daily_limit applies ), spmv_max_filesize_mb, spmv_trust_proxy, spmv_jar_sha256 | The settings in the database. |
| Classes | SPMV_Plugin, SPMV_Settings | Flow and settings page. SPMV_Plugin::adapter() returns the configured backend, SPMV_Plugin::ratelimit() the daily limit. |
The shortcode's output stands in a <template> within <div class="spmv-host"> and is moved by the script into a shadow root. The theme's stylesheets therefore do not reach it. The text domain is einvoice-validator-for-mustang, the translations are in the folder languages.
11 · Versions
No change log is included with the plugin in this version. The source code shows the following:
| Version | What was added |
|---|---|
| 1.6.1 | A note above the report says when the invoice names an edition Mustang does not know yet, such as XRechnung 4.0. The report and its notes speak of the "result" of a check. |
| 1.6.0 | The daily limit can be set per role, with its own row for guests; 0 means no access. An invoice opened in the eInvoice Viewer from 2.35.0 gets the button "Validate with Mustang". The answers appear in the language of the page, also for logged-in users with a different profile language. |
| 1.5.2 | All of the plugin's messages are translated. |
| 1.3.0 | The setting "Design kit", shared by all eInvoice tools. |
| 1.1.5 | The format names PDF and XML are highlighted in the line below the drop zone. |
| 1.0.0 | First version: shortcode, drop zone, check, report, settings page with systemcheck and checksum. |
12 · List of images
This list shows which screenshots this manual expects and which were found in the folder screenshots/ of the package. An image is always named key.language.png, for example vm-ablage.en.png. The images show sample data only.
| Status | File | What it shows |
|---|---|---|
| – | vm-ablage.en.png | The drop zone on a WordPress page with the prompt to drag in an e-invoice or choose a file, below it the line with the formats accepted |
| – | vm-systempruefung.en.png | The section "Systemcheck" of the settings page with green ticks in all rows and the message that the validator can be started |
| – | vm-shortcode.en.png | The WordPress editor with a page containing only the shortcode in square brackets |
| – | vm-bericht.en.png | The page after a check: the drop zone at the top, below it the validation report with findings in plain language and the download button |
| – | vm-download.en.png | The report header with the label "Validation report" and the button "Download report.xml" |
| – | vm-jar-integritaet.en.png | The section "Integrity of the jar" with the two checksums "Accepted" and "On disk" and the two buttons below them |
| – | vm-einstellungen.en.png | The settings page with the section "Mustang validator": path to the jar file, Java binary, timeout, daily limit, file size, proxy header and design kit |
| – | vm-meldung-pdf.en.png | The drop zone with the red message that the dropped PDF contains no e-invoice |