Skip to main content

Decode and encode MergeID electronic invoice QR codes

Project description

qrid — Python

Decode and encode MergeID electronic invoice QR codes.

Python port of qrid/codec (PHP). All three implementations (PHP, Node.js, Python) share the same payload format and function signatures, so QR codes generated by any one of them scan correctly in the others.

Typical usage flow

sequenceDiagram
    actor Staff as Billing Staff
    participant ERP as Billing / ERP System
    participant Lib as qrid
    participant QR as Invoice QR Code
    participant App as MergeID App

    Staff->>ERP: create invoice
    ERP->>Lib: encode_qr_id(code, id, company, email, address)
    Lib-->>ERP: SVG QR code
    ERP->>QR: print / embed on invoice

    Note over App,QR: later, at point of scan
    App->>QR: scan with camera
    QR-->>App: base64 payload string
    App->>Lib: decode_qr_id(encoded)
    Lib-->>App: { v, code, id, company, email, address }
    App-->>Staff: display verified invoice identity

Installation

# Decode only (no extra dependencies)
pip install qrid

# Decode + encode SVG
pip install 'qrid[encode]'

Usage

Decode

from qrid import decode_qr_id

# `encoded` is the raw string value scanned from a MergeID QR code
payload = decode_qr_id(encoded)

print(payload["v"])       # Payload schema version (int, currently 1)
print(payload["code"])    # Installation / activity code  (e.g. "ACT-001")
print(payload["id"])      # Tax or company ID              (e.g. "3101679980")
print(payload["company"]) # Company legal name
print(payload["email"])   # Billing e-mail address
print(payload["address"]) # Physical address

decode_qr_id strips surrounding whitespace before decoding, so strings copied with accidental padding are handled transparently.

Exceptions raised:

Exception Cause
ValueError Input is not valid base64
json.JSONDecodeError Decoded bytes are not valid JSON
import json
from qrid import decode_qr_id

try:
    payload = decode_qr_id(raw)
except ValueError:
    # QR data was not base64
    ...
except json.JSONDecodeError:
    # QR data decoded but was not the expected JSON structure
    ...

Encode (requires qrid[encode])

from qrid import encode_qr_id

svg = encode_qr_id(
    code="ACT-001",
    id="3101679980",
    company="Acme Corp S.A.",
    email="billing@acme.example",
    address="123 Main St, San José, Costa Rica",
)

# Write to a file
with open("invoice_qr.svg", "w") as f:
    f.write(svg)

# Or serve directly
# Content-Type: image/svg+xml

Exceptions raised:

Exception Cause
ImportError segno is not installed (pip install 'qrid[encode]')

Payload format

The QR code data is a UTF-8 JSON object encoded as standard base64 (no line-breaks):

{
  "v": 1,
  "code": "ACT-001",
  "id": "3101679980",
  "company": "Acme Corp S.A.",
  "email": "billing@acme.example",
  "address": "123 Main St, San José, Costa Rica"
}
Field Type Description
v int Payload schema version. Currently always 1.
code str Installation or activity code that links the QR to an internal record.
id str Tax / company registration ID.
company str Legal company name (UTF-8, including accented characters).
email str Primary billing or contact e-mail address.
address str Physical address of the company.

Requirements

Dependency Version Required for
Python >= 3.9 Always
segno >= 1.6 encode_qr_id() only

Running tests

pip install 'qrid[dev]'
pytest

Publishing

Releases to PyPI are fully automated — there is no manual twine upload step:

  1. Bump version in pyproject.toml and merge to main.
  2. release.yml runs on every push to main. It reads the version from pyproject.toml; if no vX.Y.Z tag already exists for it, it runs the test suite and creates that tag plus a GitHub Release.
  3. In that same run, release.yml calls publish.yml as a reusable workflow, which re-runs the tests, builds the sdist/wheel, and uploads to PyPI using Trusted Publishing (OIDC) — no stored API token.

publish.yml is invoked directly as a job (workflow_call) rather than relying on the release: published event, because releases created with the Actions-internal GITHUB_TOKEN do not trigger other workflows via events (GitHub's anti-recursion guard). publish.yml still also accepts release: published (for a release cut by hand, e.g. from the GitHub UI) and workflow_dispatch (manual re-run) as a fallback.

Pushes to main that don't change the version are a no-op for release.yml (the tag already exists), so unrelated commits (docs, CI tweaks) don't trigger a release.

One-time PyPI setup (already done for this project, documented here for reference): add a pending trusted publisher at pypi.org/manage/account/publishing with owner Quality-XP-Development-SESSA, repository qrid-python, workflow filename publish.yml, and environment name pypi; the same pypi environment must exist under the repo's GitHub Settings → Environments.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qrid-1.0.2.tar.gz (5.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qrid-1.0.2-py3-none-any.whl (4.8 kB view details)

Uploaded Python 3

File details

Details for the file qrid-1.0.2.tar.gz.

File metadata

  • Download URL: qrid-1.0.2.tar.gz
  • Upload date:
  • Size: 5.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qrid-1.0.2.tar.gz
Algorithm Hash digest
SHA256 3cde2b5e9f216629f69ed685620e0334970fbc886e8d5b9dd5532d12fc03db1e
MD5 76af43a1ff5aca545e1dad33ec875473
BLAKE2b-256 146b2573b8a0af0ac3fabd79f88c32bd1e86d9a625d6b4991e94f719024a3774

See more details on using hashes here.

Provenance

The following attestation bundles were made for qrid-1.0.2.tar.gz:

Publisher: publish.yml on Quality-XP-Development-SESSA/qrid-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file qrid-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: qrid-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 4.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qrid-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a10b582988269636aa016b62e5b3f1a815166d7696cdd1f356499b5447de3159
MD5 6cfe64529743a88df0438e547530e130
BLAKE2b-256 525f94918dbcba66ba4418b27935cfcba9f1fea02674c62245e36bdc1a6948b1

See more details on using hashes here.

Provenance

The following attestation bundles were made for qrid-1.0.2-py3-none-any.whl:

Publisher: publish.yml on Quality-XP-Development-SESSA/qrid-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page