Receipt Signing & QR Code Generation
This document explains how to produce a ZIMRA-compliant QR code for each receipt after it has been signed via the CloudESD API.
Overview
Every signed receipt includes fields that allow you to construct a ZIMRA verification URL. This URL is encoded into a QR code and printed on the receipt, enabling anyone to scan it and verify the receipt on the ZIMRA website.
Relevant Response Fields
After calling POST /api/receipt/sign, the response contains these fields used for QR code generation:
| Field | Type | Example | Description |
|---|---|---|---|
ZimraDeviceId | int | 12345 | The ZIMRA fiscal device ID that signed the receipt |
Date | datetime | 2025-03-15T10:30:00 | The receipt date |
GlobalCounter | int | 847 | The device's global receipt counter |
VerificationCode | string | A1B2-C3D4-E5F6-7890 | 16-character hyphenated hex code |
QrCodeContent | string | (full URL) | The pre-built QR code URL (ready to use) |
Using the Pre-Built URL
The simplest approach: use the QrCodeContent field directly from the sign response. It contains the complete ZIMRA verification URL, ready to be encoded into a QR code.
QrCodeContent = "https://fdms.zimra.co.zw/0000012345150320250000000847A1B2C3D4E5F67890"
Encode this string into a QR code image using any standard QR code library.
Building the URL Manually
If you need to construct the URL yourself (e.g. from stored receipt data), the format is:
{BaseUrl}{DeviceId}{Date}{Counter}{Code}
| Component | Format | Length | Example |
|---|---|---|---|
BaseUrl | Fixed | - | https://fdms.zimra.co.zw/ |
DeviceId | Zero-padded to 10 digits | 10 | 0000012345 |
Date | ddMMyyyy | 8 | 15032025 |
Counter | Zero-padded to 10 digits | 10 | 0000000847 |
Code | Verification code with hyphens removed | 16 | A1B2C3D4E5F67890 |
Concatenated Result
https://fdms.zimra.co.zw/0000012345150320250000000847A1B2C3D4E5F67890
Pseudocode
url = BASE_URL
+ pad_left(ZimraDeviceId, 10, '0')
+ format_date(Date, "ddMMyyyy")
+ pad_left(GlobalCounter, 10, '0')
+ remove_hyphens(VerificationCode)
Verification Code
The VerificationCode is returned in the sign response in the format XXXX-XXXX-XXXX-XXXX (16 hex characters, hyphenated every 4).
For reference, it is derived from the device signature as follows:
- Take the
DeviceSignature(Base64 decoded to bytes) - Compute the MD5 hash of those bytes
- Convert to hexadecimal
- Take the first 16 hex characters
- Insert hyphens every 4 characters:
XXXX-XXXX-XXXX-XXXX
You do not need to compute this yourself -- it is provided in every sign response and get receipt response. This is documented here only for completeness.
Generating the QR Code Image
Use any QR code library to encode the URL string into an image. Examples:
JavaScript (using qrcode npm package)
const QRCode = require('qrcode');
const qrContent = receiptResponse.QrCodeContent;
// or build manually:
// const qrContent = `https://fdms.zimra.co.zw/${deviceId}${date}${counter}${code}`;
// Generate as data URL for display in HTML
const dataUrl = await QRCode.toDataURL(qrContent);
// Generate as file
await QRCode.toFile('receipt-qr.png', qrContent);
Python (using qrcode pip package)
import qrcode
qr_content = receipt_response["QrCodeContent"]
img = qrcode.make(qr_content)
img.save("receipt-qr.png")
C# (using QRCoder NuGet package)
using QRCoder;
var qrContent = receiptResponse.QrCodeContent;
using var qrGenerator = new QRCodeGenerator();
using var qrCodeData = qrGenerator.CreateQrCode(qrContent, QRCodeGenerator.ECCLevel.Q);
using var qrCode = new PngByteQRCode(qrCodeData);
byte[] qrCodeImage = qrCode.GetGraphic(5);
File.WriteAllBytes("receipt-qr.png", qrCodeImage);
Printing the Receipt
A compliant fiscal receipt should display:
- QR code image -- encoded from the verification URL
- Verification code -- the
VerificationCodefield (e.g.A1B2-C3D4-E5F6-7890) - Manual verification note -- direct customers to
https://receipt.zimra.orgfor manual verification using the verification code
Example receipt footer layout
Verification Code: A1B2-C3D4-E5F6-7890
Verify this receipt at https://receipt.zimra.org
[QR CODE IMAGE]
Complete Worked Example
Given a sign response with:
| Field | Value |
|---|---|
ZimraDeviceId | 67890 |
Date | 2025-07-22T14:05:30 |
GlobalCounter | 1523 |
VerificationCode | F4E3-D2C1-B0A9-8765 |
QR code URL construction:
Base URL: https://fdms.zimra.co.zw/
Device ID: 0000067890 (67890 padded to 10 digits)
Date: 22072025 (22 Jul 2025 as ddMMyyyy)
Counter: 0000001523 (1523 padded to 10 digits)
Code: F4E3D2C1B0A98765 (hyphens removed)
Full URL: https://fdms.zimra.co.zw/0000067890220720250000001523F4E3D2C1B0A98765
This matches the value that would be in the QrCodeContent response field.