Engineering9 min read·EN

Extracting XBRL from Bulgarian ESEF filings — and why it's harder than Western Europe

BSE issuers ship iXBRL inline with PDF cover pages, mixed taxonomies, and Cyrillic-named contexts. Here's how we get to a clean JSON in <30s.

Published Updated

Most XBRL tooling is calibrated for Western European filers — quarterly reports in English, cover pages in HTML, contexts named in ASCII. The Bulgarian Stock Exchange does none of that. When we set out to ship <30s ingest latency on BSE filings, we found we'd be rewriting most of the stack.

Why CEE is different

Three things break the assumptions baked into off-the-shelf iXBRL parsers when you point them at BSE, WSE, or BVB:

  • Mixed-language filings. A single Bulgarian quarterly often ships a Bulgarian narrative, an English summary, and an XBRL package whose context names are in cyrillic-snake-case.
  • Cover-page PDF wrappers. Issuers attach a regulator-mandated PDF cover page before the iXBRL document, so the document we receive is a multipart blob and not a single .xhtml.
  • Taxonomy drift. ESEF mandates IFRS, but local extensions for Bulgarian banking disclosures are non-trivial and update yearly. Our parser handles three Bulgarian extension taxonomies live, plus archived versions for restatements.

We treat every filing as a multipart document — not a file. The cover, the narrative, and the iXBRL travel together, and the citation graph has to know which one a number came from.

— Internal design doc, Nov 2025

ESEF the Bulgarian way

The standard says iXBRL. The implementation says iXBRL plus a PDF cover, plus a signed XML manifest, plus the issuer's own custom extension namespace. We unpack each as a separate entity in our document graph and reconcile facts across them at extraction time. Here's a representative ingest log:

$ ceewire ingest --debug bash
[2026-05-08T09:14:02Z] FETCH    bse://filing/2438211       (4.2MB, application/zip)
[2026-05-08T09:14:03Z] DEMUX    cover.pdf, narrative.docx, ixbrl.xhtml, manifest.xml
[2026-05-08T09:14:04Z] PARSE    ixbrl.xhtml  contexts=412 facts=1,847 taxonomy=ESEF+BGext-2025
[2026-05-08T09:14:06Z] NORMALIZE  cyrillic_contexts→ascii  units→EUR  signs→IFRS
[2026-05-08T09:14:11Z] EXTRACT  language=BG  translated=EN  preserved_original=true
[2026-05-08T09:14:14Z] EMIT     filing/2438211  JSON  ingest_latency=24.6s

Cyrillic-named contexts

The XBRL spec doesn't forbid non-ASCII context IDs, but most parsers assume them. Our normalization pass deterministically transliterates each context to ASCII while preserving the original in a sidecar field — so a query for revenue_q1 still resolves, and a Bulgarian-speaking compliance officer can audit the original mapping.

Benchmarks

We measure ingest latency at the 50th and 95th percentile over the last 30 days of BSE Q1 filings (n = 847). Numbers are seconds from publication to JSON availability on the API:

ExchangeP50P95N
BSE (Bulgaria)24.6s41.2s847
WSE (Poland)18.1s32.7s2,140
BVB (Romania)21.4s39.8s612

What we're working on

Next week: We are currently testing the company filings information flow for companies listed on the Romania's BVB stock exchange. In the initial stage we are going to focus on the companies covered in the BET-XT index. If you have feedback on the JSON schema, we read every reply at [email protected].

TAGS#XBRL#ESEF#BSE