Pantheon ERP · Croatian fiscalization

Order in. Fiscalized invoice out.

A production-grade integration service that connects a webshop to the Pantheon ERP, with automated Croatian fiscalization and invoice delivery by email. From order to fiscalized invoice, with no manual step.

Role
Backend architecture · integration build · delivery
Stack
NestJS · BullMQ · PostgreSQL · MS SQL Server
Status
In production
Delivery
Docker image, on the client's infrastructure or as a managed service
Webshop order → fiscalized invoice · Pantheon ERP0manual steps123456Webshopcanonical JSONMiddleware202 Accepted, queuedPantheon ERPstored proceduresFiscalizationZKI · signed XML · JIRInvoice PDFfiscal data and QRCustomer inboxemailed over SMTPIn production: one-way middlewareTwo-way sync, first connector WooCommerce: in developmentOrder → fiscalized invoice1Webshoporder sent as canonical JSON2Middleware202 Accepted, job queued3Pantheon ERPorder and invoice via stored procedures4FiscalizationZKI, signed XML, JIR from FINA5Invoice PDFfiscal data and QR code6Customer inboxemailed over SMTP0manual steps
The whole flow runs with no manual steps: order ingest, customer ensure, ERP order and invoice, fiscalization, PDF, email.

What it needed to solve

In most installations a webshop and the Pantheon ERP are two separate worlds. Somebody has to carry every sale from one to the other.

01Orders get re-keyed into the ERP by hand.

02Invoices are issued manually, one by one.

03Croatian fiscalization, a legal requirement, sits outside the flow or in a separate tool.

04The result: a lag between order and invoice, re-keying errors, and the same sequence of steps, every day.

What was needed was a service that carries every order to a fiscalized invoice without anyone touching it.

What was needed was a service that carries every order to a fiscalized invoice without anyone touching it.

How we built it

Forward-only. Simple to reason about, hard to knock over.

The webshop sends orders in one direction and the middleware does the rest: a clean contract on the front, safe writes and fiscalization on the back.

01

Our own API contract, answered at once.

The middleware defines the order format: canonical JSON, published as an OpenAPI spec and validated at the edge. Every order is checked and queued, and the webshop gets 202 Accepted immediately. An ERP outage never breaks checkout.

OpenAPI specpublished, versionedWebshopsends the orderMiddleware edgetoken authenticationschema validationduplicate check→ job queuedJob queueRedisJSON202The webshop never waits on the ERP.An ERP outage doesn't break checkout.

Swipe the diagram sideways.

02

Safe writes into the ERP.

Every write goes through Pantheon stored procedures, never a direct INSERT into ERP tables. Writes run in transactions, document numbering stays owned by the ERP, and access runs through a dedicated integration user with least privilege.

Workerprocess 02Pantheon ERPMS SQL ServerERP tablesnever written directlystored procedures · in a transactiondirect INSERTA dedicated integration user with least privilege.Document numbering stays owned by the ERP.

Swipe the diagram sideways.

03

Croatian fiscalization, built in-house.

ZKI generation, digitally signed XML, the exchange with FINA, the JIR and a QR code on the invoice. No intermediary and no third-party fiscalization service.

Invoice in Pantheonready to fiscalizeZKI generatedprotective codeSigned XMLXML-DSigFINAfiscalization serviceJIR returnedunique invoice IDQR on the invoiceprinted with the JIRNo intermediary, no third-party fiscalization service.The demo to production certificate cutover is a documented procedure.

Swipe the diagram sideways.

04

The invoice lands in the inbox.

A PDF rendered by headless Chromium from templates, carrying the fiscal data and QR code, emailed to the customer over SMTP with an internal copy.

Invoice templateHandlebarsFiscal dataZKI, JIR, QR codeHeadless Chromiumrenders the PDFInvoiceZKIJIRSMTPCustomer inboxplus an internal copySent the moment the sale is fiscalized.

Swipe the diagram sideways.

05

Resilient, idempotent, observable.

The same order sent twice never creates two documents. Retries with exponential backoff, dead-letter handling and automatic ERP reconnect. A correlation ID follows every order from the HTTP request to the sent email.

Idempotentsame ordersent againone documentResilientJobRetryexponential backoffDead letterrecorded, re-queuedObservableERPDatabaseQueueSMTPHealth and readiness probes for every dependency,and one correlation ID from HTTP request to sent email.

Swipe the diagram sideways.

Two processes, one codebase.

The service runs as two independent processes from a single codebase, so each can scale and fail on its own without taking the other down.

Process 01Process 02WebshopsourceHTTP Receivervalidates, enqueuesRedis QueuebrokerWorkerERP, fiscal, PDF, emailPantheonERP, source of truthCustomerinvoice PDFPostgreSQL · idempotency keys, ID correlation, auditJSONenqueue202 Acceptedjobstored procsfiscalized PDF, by email

Swipe the diagram sideways.

Process 01

Authenticates and validates incoming orders, checks for duplicates, enqueues the job and returns 202 Accepted immediately. The webshop never waits on the ERP.

Process 02

Ensures the customer, syncs the order into Pantheon, runs fiscalization, renders the PDF invoice and sends the email, with retries and backoff at every step and a dead-letter record when even that doesn't get through.

The ERP is the source of truth. The middleware holds no business data, only what it needs to never lose or repeat a job.

Two ways to host it.

Option 01

On the client's infrastructure

The service runs inside their network, next to Pantheon, without exposing the ERP outward. They get the image, the docker-compose configuration and runbooks for deploy, backup and rollback. Data never leaves their environment.

Option 02

On ours, as a managed service

We run, monitor and maintain it, with separate production and test environments. The client gets a URL and a token and never thinks about servers, updates or certificates.

Either way it is the same code, API contract and documentation. Moving from one option to the other needs no changes to the webshop or the ERP.

Least privilege, nothing in the clear.

  • Token authentication on incoming requests, and anything that fails the schema is rejected.
  • No direct writes into ERP tables; a dedicated integration user instead of an admin account.
  • Secrets and certificates come from the environment only, never the repository or the image.
  • Source-free delivery: the app ships compiled to V8 bytecode, so readable source never reaches the client's infrastructure.

Chosen for reliability.

Runtime
Node.js 20+ · TypeScript 5, strict
Framework
NestJS 10
Job queue
BullMQ + Redis
State store
PostgreSQL + Prisma
ERP access
MS SQL Server, stored procedures
Invoice PDF
Headless Chromium + Handlebars
Fiscalization
XML-DSig · node-forge · QR codes
Observability
pino · OpenAPI · Bull Board
Delivery
Docker + Docker Compose

Built as a product, ready for the next merchant.

The contract facing the webshop, the Pantheon access layer and the fiscalization layer are generic. What differs from client to client, credentials, certificate, warehouses, tax rates, invoice templates and business rules, is environment configuration.

Onboarding a new Pantheon user comes down to configuration and a check on the test environment, not a new development cycle, whatever platform powers the webshop.

  • Order ingest
  • Customer ensure
  • ERP order and invoice
  • Fiscalization, ZKI and JIR
  • Invoice PDF rendered
  • Email delivery
  • Containerized and observable
  • Production certificate cutover
  • Separate test environment

Two systems that should be talking to each other?

Tell us what you are re-keying by hand. We'll come back within one business day with a clear plan.

Next project · Integration

Webshop × Pantheon

A two-way middleware that keeps a webshop and the Pantheon ERP in sync: orders, statuses, stock and fiscalized invoices, with no manual work at all.

Webshop ⇄ Pantheon ERP · two-way sync123456Webshoporder eventConnectorWooCommercePantheon ERPstored proceduresFiscalizationZKI · JIRInvoice PDFfiscal data and QRCustomer inboxemailed over SMTP← statuses · stock · prices · products, back to the webshopIn development: the WooCommerce connectorIntegration-tested against a live Pantheon instance