<?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: Rick</title>
    <description>The latest articles on DEV Community by Rick (@rickle).</description>
    <link>https://dev.to/rickle</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%2F1027757%2Fee39a3f7-3921-4a2a-8250-7e6e6a9d0d22.jpeg</url>
      <title>DEV Community: Rick</title>
      <link>https://dev.to/rickle</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rickle"/>
    <language>en</language>
    <item>
      <title>How to Parse a Chinese VAT Invoice (Fapiao) with Code — Fields, Formats, and Pitfalls</title>
      <dc:creator>Rick</dc:creator>
      <pubDate>Sun, 01 Nov 2026 16:22:19 +0000</pubDate>
      <link>https://dev.to/rickle/how-to-parse-a-chinese-vat-invoice-fapiao-with-code-fields-formats-and-pitfalls-2ba2</link>
      <guid>https://dev.to/rickle/how-to-parse-a-chinese-vat-invoice-fapiao-with-code-fields-formats-and-pitfalls-2ba2</guid>
      <description>&lt;p&gt;If your software touches anyone who buys from, sells to, or operates in China, sooner or later a &lt;strong&gt;fapiao&lt;/strong&gt; (发票) lands in your inbox — usually as a crooked phone photo of a printed A5 sheet, or a PDF that looks like a spreadsheet form. Your user wants it in your expense system as structured data. Generic OCR gives you a wall of Chinese text and leaves the hard part to you.&lt;/p&gt;

&lt;p&gt;I spent the last few weeks building a parser for these documents. This post is everything I learned about their structure — useful even if you end up writing your own extractor.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a fapiao actually is
&lt;/h2&gt;

&lt;p&gt;A fapiao is not a receipt your seller prints freely. It is a tax-controlled document issued through China's tax system, and it is the only voucher the tax bureau accepts for VAT deduction and expense reimbursement. The two types you will meet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;增值税专用发票&lt;/strong&gt; (special VAT invoice) — businesses use it to deduct input VAT. Strictest layout.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;增值税普通发票&lt;/strong&gt; (general VAT invoice) — for everyone else.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are increasingly issued as &lt;strong&gt;全电发票&lt;/strong&gt; (fully digital e-invoices): no paper, no invoice code, just a 20-digit invoice number. If your parser assumes the classic layout, the digital ones will break it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fields, and where they hide
&lt;/h2&gt;

&lt;p&gt;A classic VAT invoice carries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;发票代码&lt;/strong&gt; (invoice code, 10–12 digits) and &lt;strong&gt;发票号码&lt;/strong&gt; (invoice number, 8 digits) — top right. On fully digital invoices, only the 20-digit number exists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;开票日期&lt;/strong&gt; — issue date, top right under the number.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;校验码&lt;/strong&gt; — a 20-digit check code, used on the tax bureau's verification site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;购买方 / 销售方&lt;/strong&gt; (buyer / seller) blocks: name plus &lt;strong&gt;纳税人识别号&lt;/strong&gt; — the tax ID, for companies the 18-character Unified Social Credit Code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line items&lt;/strong&gt;: name (often prefixed with a category like &lt;code&gt;*信息技术服务*&lt;/code&gt;), specification, unit, quantity, unit price, amount.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;税率 / 税额&lt;/strong&gt; — VAT rate (13% / 9% / 6% / 3% / 1% depending on category) and tax per line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;价税合计&lt;/strong&gt; — the tax-inclusive total, printed &lt;strong&gt;twice&lt;/strong&gt;: in digits (小写) and in formal Chinese capital numerals (大写), e.g. &lt;code&gt;壹仟圆整&lt;/code&gt; for ¥1,000.00.&lt;/li&gt;
&lt;li&gt;A red &lt;strong&gt;发票专用章&lt;/strong&gt; (invoice seal) stamped over the seller block, frequently overlapping the text you need.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pitfalls that bite every first implementation
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The two totals must agree — use that.&lt;/strong&gt; 金额 (pre-tax) + 税额 (tax) = 价税合计 (total), and the 大写 amount must equal the 小写 one. These two independent cross-checks catch most OCR digit errors for free. The capital-numeral set (壹贰叁肆伍陆柒捌玖拾佰仟圆角分整) is small; parsing it is an afternoon's work and pays for itself immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Red-ink invoices exist.&lt;/strong&gt; A 红字发票 is a credit-note invoice with negative amounts, issued to void or correct a blue one. If your pipeline sums invoices, treat red ones as first-class citizens, not parse errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "same" family isn't the same document.&lt;/strong&gt; Train e-tickets (铁路电子客票), flight itineraries (航空运输电子客票行程单) and taxi receipts share the reimbursement workflow but have completely different fields (passenger ID, train number, fare class…). Auto-detect the document type first, extract second.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The seal is part of the image.&lt;/strong&gt; The red stamp sits on top of seller name and tax ID. OCR engines vary wildly here; expect to try preprocessing (and to distrust low-confidence characters in the stamped zone).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The QR code is a cheat code.&lt;/strong&gt; The QR printed on the invoice encodes the code, number, pre-tax amount, date and check code. When it's legible, decode it and use it to verify (or replace) your OCR'd key fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tax IDs are validatable.&lt;/strong&gt; The 18-char Unified Social Credit Code has a check digit (GB 32100). Validate before you store — a misread character otherwise poisons your accounting data silently.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The approach that worked for me
&lt;/h2&gt;

&lt;p&gt;OCR for the text layer → anchor-based field extraction (the labels 名称 / 税号 / 价税合计 are stable even when layouts shift) → cross-validation of every numeric field (line sums, totals, 大写 vs 小写, check digits) → only then emit JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"document_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vat_invoice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"invoice_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"044002100111"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"invoice_number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"38291047"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"issue_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-10-28"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"buyer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tax_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"91310000XXXXXXXXXX"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"seller"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tax_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"91440101XXXXXXXXXX"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*信息技术服务*软件开发费"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;943.40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tax_rate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.06&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tax"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;56.60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount_excl_tax"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;943.40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tax_total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;56.60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_incl_tax"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1000.00&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try it / skip the build
&lt;/h2&gt;

&lt;p&gt;I packaged this parser as a small API (&lt;a href="https://rapidapi.com/keli-H8hoL8M2C/api/china-invoice-ocr-fapiao-parser?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=exp3" rel="noopener noreferrer"&gt;China Invoice OCR — Fapiao Parser&lt;/a&gt; on RapidAPI — it also auto-detects train tickets, flight itineraries and taxi receipts). If you just want to see the extraction on a real document, there's a &lt;a href="https://tools.43-128-141-80.sslip.io/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=exp3" rel="noopener noreferrer"&gt;free web demo&lt;/a&gt;: upload an invoice image, get the field table back, no signup.&lt;/p&gt;

&lt;p&gt;Full disclosure: that's my own API — but honestly, if your volume is low, the DIY route above is completely viable, and the cross-validation tricks matter more than which OCR engine you pick.&lt;/p&gt;

&lt;p&gt;What did I miss? If you've fought fapiao (or the fully digital formats) in production, I'd like to hear which pitfall got you.&lt;/p&gt;

</description>
      <category>api</category>
      <category>ocr</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
