Mutabiq checks Saudi ZATCA Phase 2 e-invoice XML before you submit it: pre-validation against published ZATCA requirements, not an approval by the authority. This page explains one rule, MTB-PIH-01.
Five checks a month on the Free plan. The file is checked in memory and is never stored.
No published ZATCA clause
No clause in ZATCA's published validation rules tests what the previous invoice hash contains: the two that read it check that it is present and what it is tagged as, not what it holds. Mutabiq checks its shape against what ZATCA's XML Implementation Standard, section 13.3.1, specifies — a base64-encoded SHA-256 — and reports a finding at the Warning level. A finding under this rule is Mutabiq's own check, not a rule ZATCA runs.
Reported at
Warning
What Mutabiq reports
One entry for each way this rule can be reported.
Reported as
What kind of value was found — empty, not_15_digits and the like — never the value itself.
Previous invoice hash is not base64
Reported asnot_base64not base64
What is wrong
The previous invoice hash (KSA-13) is not valid base64, so it cannot be the base64-encoded digest the field is defined to hold. Either its length is not a multiple of four or it contains characters outside the base64 alphabet. This is reported as a risk rather than as a rejection, and the reason is worth knowing: no assertion in ZATCA's published rule set decodes this value or checks its shape at all. The published checks are that the element exists, is not empty, declares a media type of text/plain, and is at most 255 characters. So ZATCA accepts a previous invoice hash that is not a hash. But the XML Implementation Standard and the Security Features Implementation Standards both define the field as a base64-encoded SHA-256, so a value that is not base64 is wrong by ZATCA's own definition of the field even though the checker will pass it.
What to check in your ERP
The usual causes are a value carrying characters base64 does not use - the hyphen and underscore of the URL-safe variant are the common pair - a data URI or file path written where the value belongs, a plain-text placeholder, and line breaks or spaces inside the value, which an XML writer set to pretty-print will introduce by wrapping a long value across indented lines. Note that a raw hexadecimal digest is not reported here: 64 hexadecimal characters happen to be valid base64, so that case appears as the other previous-invoice-hash finding instead. Fix this where the hash is encoded, in the step that writes the chain, rather than in the exported file.
Previous invoice hash is not shaped like a SHA-256
Reported asnot_a_sha256not the shape of a SHA-256 digest
What is wrong
The previous invoice hash (KSA-13) is valid base64, but it is not a SHA-256 in either of the two forms ZATCA's own documentation describes - and there are two because one page of that documentation describes the field twice and the descriptions disagree. The XML Implementation Standard gives the construction: hash the invoice to a binary object, then base64-encode that binary object. A SHA-256 is 32 bytes, so that yields 44 base64 characters. The very next sentence on the same page gives the value to use for the first invoice in a chain, beginning NWZlY2ViNjZm and ending in a double equals sign, and calls it the base64-encoded SHA-256 of the character 0. It is not that by the construction just given: it is 88 characters, and it decodes to the 64-character hexadecimal text of the digest rather than to the digest's 32 bytes. Because the standard specifies both on the same page, Mutabiq accepts both - a value that decodes to 32 bytes, and a value that decodes to a 64-character hexadecimal digest - and this finding means the value is neither. It is reported as a risk rather than as a rejection, because nothing in ZATCA's published rule set decodes this value: the published checks are existence, non-emptiness, a media type of text/plain and a 255-character ceiling, so ZATCA accepts the document as it stands. Mutabiq does not recompute the hash, so this says the value's shape is wrong; it says nothing about whether it is the right hash.
What to check in your ERP
Check the hashing step in your e-invoicing module, and two settings in it. The first is the algorithm: SHA-1 gives 20 bytes and SHA-512 gives 64, and both encode to a well-formed base64 of the wrong length, so a module left on an older default lands here. The second is the output encoding, which is the more common of the two - a digest written as hexadecimal text and then base64-encoded is the 88-character form and is accepted, but a raw hexadecimal digest written straight into the field is not, and it reaches this finding rather than the not-base64 one because 64 hexadecimal characters are accidentally valid base64. Also check what is being hashed at all: base64 of the previous invoice's whole XML, or of a description of it, is well-formed base64 of the wrong length and appears here. For the first invoice in a chain, use the value the XML Implementation Standard publishes rather than an empty value or a placeholder.
A worked example
A synthetic document from the measured test corpus that trips this rule, shown where it differs from one that passed. Mutabiq's report names the class of the value, never the value itself.