<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gabriel Petrescu</title>
    <description>The latest articles on DEV Community by Gabriel Petrescu (@gabrielm92).</description>
    <link>https://dev.to/gabrielm92</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4097911%2F14dc9568-bc8f-4755-bb80-09f28d46f0ce.png</url>
      <title>DEV Community: Gabriel Petrescu</title>
      <link>https://dev.to/gabrielm92</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gabrielm92"/>
    <language>en</language>
    <item>
      <title>Every ANAF e-Factura rejection, explained — a developer's field guide</title>
      <dc:creator>Gabriel Petrescu</dc:creator>
      <pubDate>Fri, 28 Aug 2026 06:54:40 +0000</pubDate>
      <link>https://dev.to/gabrielm92/every-anaf-e-factura-rejection-explained-a-developers-field-guide-lom</link>
      <guid>https://dev.to/gabrielm92/every-anaf-e-factura-rejection-explained-a-developers-field-guide-lom</guid>
      <description>&lt;p&gt;Romania's e-Factura is mandatory, and the hard part isn't the &lt;em&gt;idea&lt;/em&gt; — it's ANAF's stack. You hit SOAP endpoints, an OAuth + digital-certificate lifecycle, and rejection codes that read like hex dumps. This is the field guide I wish I'd had: what actually makes ANAF reject an invoice, and how to read the error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does ANAF reject my e-Factura?
&lt;/h2&gt;

&lt;p&gt;Almost every rejection falls into one of four buckets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Schema / RO_CIUS validation&lt;/strong&gt; — the XML is well-formed but breaks a business rule of the Romanian CIUS (the national customization of the EU standard, EN 16931). This is the most common and the most cryptic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing or malformed mandatory fields&lt;/strong&gt; — a required party identifier, tax category, or total is absent or in the wrong shape.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Certificate / OAuth lifecycle&lt;/strong&gt; — your token expired, the cert isn't registered in SPV, or the auth handshake failed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SPV submission state&lt;/strong&gt; — the document was accepted for processing but later rejected, and you have to poll for the verdict.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you can classify a failure into one of these four, you already know where to look.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is RO_CIUS and why does it fail when my XML "looks fine"?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;RO_CIUS is Romania's Core Invoice Usage Specification&lt;/strong&gt; — a national profile on top of the EU standard &lt;strong&gt;EN 16931&lt;/strong&gt;. Your XML can be valid UBL &lt;em&gt;and still&lt;/em&gt; violate a RO_CIUS rule, because CIUS adds country-specific constraints the base schema doesn't enforce. Typical categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Party identification&lt;/strong&gt; — the supplier/customer tax ID (CUI/CIF) or registration number missing, malformed, or inconsistent with the VAT-payer flag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tax breakdown&lt;/strong&gt; — the VAT category codes and the tax subtotals don't reconcile with the document totals (a rounding or category mismatch).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Currency &amp;amp; dates&lt;/strong&gt; — wrong currency code, or a date format/issue-date rule the CIUS tightens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mandatory business terms&lt;/strong&gt; — an EN 16931 business term (the "BT-…" fields) that RO_CIUS marks required is absent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trap: the &lt;em&gt;base&lt;/em&gt; UBL schema passes, so your XML editor says "valid," but ANAF's CIUS layer rejects it. You need a validator that checks the &lt;strong&gt;RO_CIUS business rules&lt;/strong&gt;, not just the schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I read a cryptic ANAF error code?
&lt;/h2&gt;

&lt;p&gt;The fastest path is to run the invoice through a validator that &lt;strong&gt;translates the rule into plain language&lt;/strong&gt; instead of echoing a rule ID. A raw message like a bare rule reference tells you nothing; what you want is "line 4's VAT category is 'exempt' but there's no exemption reason code" — the &lt;em&gt;what&lt;/em&gt; and the &lt;em&gt;where&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You can paste an invoice into the &lt;strong&gt;free Fiscura validator&lt;/strong&gt; (&lt;a href="https://fiscura.ro/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=error_guide" rel="noopener noreferrer"&gt;fiscura.ro&lt;/a&gt;) and get exactly that — every RO_CIUS / EN 16931 error explained in plain RO/EN, no key and no card. (Full disclosure: I build Fiscura. The validator is genuinely free and the explanations are the whole point of this article.)&lt;/p&gt;

&lt;h2&gt;
  
  
  What about the certificate + OAuth + SPV part?
&lt;/h2&gt;

&lt;p&gt;This is the other half of the pain, and it's orthogonal to your XML:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You authenticate to ANAF's &lt;strong&gt;SPV&lt;/strong&gt; with a qualified digital certificate.&lt;/li&gt;
&lt;li&gt;You manage an &lt;strong&gt;OAuth token lifecycle&lt;/strong&gt; (obtain, refresh, handle expiry mid-batch).&lt;/li&gt;
&lt;li&gt;You &lt;strong&gt;submit&lt;/strong&gt; the invoice, get an upload index, and then &lt;strong&gt;poll&lt;/strong&gt; for the processing verdict — acceptance isn't synchronous.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that is business logic you want to own. It changes, it's under-documented, and a single expired token silently fails a batch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can I skip building all of this?
&lt;/h2&gt;

&lt;p&gt;Yes — that's the shortcut. Instead of hand-rolling SOAP + cert + polling, it's &lt;strong&gt;one REST call&lt;/strong&gt;, or a few lines with the SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @gaperi/fiscura-sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API covers the full path: &lt;strong&gt;validate&lt;/strong&gt; RO_CIUS, &lt;strong&gt;generate&lt;/strong&gt; compliant UBL 2.1, &lt;strong&gt;submit&lt;/strong&gt; to ANAF SPV (using your own ANAF cert), &lt;strong&gt;convert&lt;/strong&gt; UBL↔CII, and even &lt;strong&gt;extract&lt;/strong&gt; a PDF invoice into structured JSON. There's a free tier (100 calls/day, no card), a self-serve developer account, and a &lt;a href="https://fiscura.ro/docs?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=error_guide" rel="noopener noreferrer"&gt;quickstart in the docs&lt;/a&gt;. It's EU-hosted (Frankfurt), so it's GDPR-clean.&lt;/p&gt;

&lt;p&gt;Want to see it run before you sign up? Clone the examples — a live, no-signup validation call in seconds (curl + plain-fetch JS + the SDK): &lt;strong&gt;&lt;a href="https://github.com/gaperi-consult/fiscura-examples" rel="noopener noreferrer"&gt;github.com/gaperi-consult/fiscura-examples&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Classify the rejection: &lt;strong&gt;RO_CIUS validation · missing field · cert/OAuth · SPV state&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Your XML being schema-valid doesn't mean it's &lt;strong&gt;RO_CIUS-valid&lt;/strong&gt; — check the business rules.&lt;/li&gt;
&lt;li&gt;Read errors in &lt;strong&gt;plain language&lt;/strong&gt;, not rule IDs — &lt;a href="https://fiscura.ro/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=error_guide" rel="noopener noreferrer"&gt;paste one into the free validator&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Don't hand-build the ANAF cert/OAuth/SPV lifecycle unless you have to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Informational developer tooling, not tax advice. If you integrate e-Factura, I'd love to hear which ANAF error wasted the most of your time.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>efactura</category>
      <category>romania</category>
      <category>api</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
