Bilko HR eRačun — sveRačun (PostLink) Integration & Status Model
Overview
Provider: sveRačun by PostLink d.o.o. (Velika Gorica, HR).
Contact: David Krišto [email protected], Ivan Jurić [email protected].
API docs: https://sveracun-public-api.redocly.app/
Replaces the abandoned Storecove plan (MC #8675, not approved). CEO accepted sveRačun partnership 2026-06-11.
Current state: adapter MERGED to main, GATED/DISABLED (SVERACUN_HR_LIVE=false, adapter_config sveracun-hr-fisk enabled=FALSE). Live activation pending (MC #103443).
API
| Operation | Endpoint | Notes |
|---|---|---|
| Submit document | POST https://test.sveracun.hr/api/rest/v1/documents/send | Auth header: Authorization: <raw-api-key> (apiKey scheme, NOT Bearer). Body: raw UBL 2.1 XML (application/octet-stream). Response: {"documentId":"<hex>"}. PROD base URL differs from TEST. |
| Internal status | POST /rest/v1/documents/getInternalStatus | Poll only — no webhook. |
| External status | POST /rest/v1/documents/getExternalStatus | Provider also references documents/getStatus. |
Two-Stage Processing (per David Krišto / PostLink)
Etapa 1 — Basic parse: the initiator OIB (the OIB that calls send, tied to the API key) MUST equal the sender OIB inside the UBL XML, plus recipient/document-type/process checks. Mismatch results in status FAILED.
Etapa 2 — Full routing: validation vs Porezna uprava validator; recipient access-point lookup; SBD preparation; AS4 exchange (waits 5 min for recipient access point; on unavailability retries up to 24× every 30 min); outbound fiscalization; archiving.
Status Model (Authoritative — correct as of 2026-06-11)
Internal statuses
| Status | Meaning |
|---|---|
NEW | Inbound-only — document available to pick up. |
OK | Processed successfully by sveRačun. |
FAILED | Processing interrupted (e.g. sender OIB mismatch, parse error). |
UNKNOWN | Currently being processed. |
UNDELIVERABLE | Recipient not registered in AMS (access-point lookup failed). |
External (fiscalization) statuses
| Status | Meaning |
|---|---|
FISCALIZATION:OK | Fiscalization succeeded. |
FISCALIZATION:ERROR | Fiscalization failed. |
null | Not yet forwarded to fiscalization. |
FISCALIZATION_PAYMENT_REPORT:OK|ERROR | Payment report fiscalization result. |
FISCALIZATION_REJECTION_REPORT:OK|ERROR | Rejection report fiscalization result. |
FISCALIZATION_NOT_DELIVERED_REPORT:OK|ERROR | Not-delivered report fiscalization result. |
Bilko decision: composite outcome classification
| Outcome | Condition |
|---|---|
| SUCCESS | internal = OK AND external = FISCALIZATION:OK |
| FAILURE | internal = FAILED | UNDELIVERABLE, OR external = FISCALIZATION:ERROR | any REJECTION_REPORT | any NOT_DELIVERED_REPORT |
| PENDING | internal = UNKNOWN | NEW, OR external = null |
How do we know the invoice arrived? Poll until external status is
FISCALIZATION:OK(success) or any*_REPORT/ERRORterminal state (failure). There is NO webhook from sveRačun.
Implementation
Source files
apps/api/src/main/kotlin/no/alai/bilko/country/hr/SveRacunHttpClient.kt— HTTP client (submit, getInternalStatus, getExternalStatus).apps/api/src/main/kotlin/no/alai/bilko/country/hr/SveRacunHrEInvoiceAdapter.kt— serialize, submit, pollStatus; unifiedmapStatusPair(internal, external)logic.PluginHR.kt—EINVOICE_SUBMIT= BETA, gated bySVERACUN_HR_LIVEflag.db/migrations/V74__sveracun_adapter_config.sql— Flyway migration; registers adapter_config recordsveracun-hr-fisk.
Key implementation detail
serialize() forces UBL AccountingSupplierParty OIB to equal SVERACUN_SENDER_VAT (e.g. HR91276104352). If this env var is unset the method is fail-closed (throws before submitting). This prevents Etapa-1 sender-OIB mismatch failures.
Configuration & secrets
| Variable | Purpose | Where stored |
|---|---|---|
SVERACUN_API_KEY | API authentication (raw key, not Bearer) | GCP Secret: bilko-sveracun-test-api-key (TEST); separate PROD secret to be provisioned. |
SVERACUN_BASE_URL | Base URL (test vs prod differs) | Cloud Run env |
SVERACUN_SENDER_VAT | Sender OIB for UBL XML + Etapa-1 initiator match | Cloud Run env |
SVERACUN_HR_LIVE | Feature gate (false = adapter disabled) | Cloud Run env |
SECURITY: Never commit or log the actual API key value. Always retrieve from GCP Secret Manager at runtime.
PRs & tests
- PR #346 — initial integration.
- PR #348 — status-model correction (MC #103445).
- 42 unit tests:
SveRacunHrEInvoiceAdapterTest.
Verification
Proveo independent PASS — live TEST submit returned HTTP 200, internalStatus=UNKNOWN (processing) after Etapa-1 sender-OIB fix. Prior FAILED result was caused by sender/initiator OIB mismatch before the serialize() fix. Evidence: /tmp/evidence-103445/.
Activation Checklist (MC #103443 — NOT yet done)
- PostLink confirms our OIB
91276104352is a registered TEST sender (and separately, PROD sender). - Independent green re-test:
internalStatus=OKend-to-end (both Etapa 1 and 2). - Provision PROD sveRačun API key as GCP Secret.
- Flip adapter_config
enabled=true+SVERACUN_HR_LIVE=true+SVERACUN_SENDER_VATin Cloud Run (PROD environment). - ZAKON PI2 deploy + Proveo live-activation verification.
- GA compliance review before statutory HR eRačun filing obligations take effect.
Related MC Tasks
- MC #103434 — sveRačun integration (build).
- MC #103445 — Corrected status model (PR #348).
- MC #103443 — Live activation (pending — do NOT mark done until activation checklist complete).
- MC #8675 — Abandoned Storecove plan (not approved; superseded).
No comments to display
No comments to display