Code Examples

Ready-to-use code snippets for the MOR Fiscal API

Create a Fiscal Receipt

Issue a tax-compliant receipt via the MOR API. Supports Category A (15% VAT) and Category B (0% VAT) merchants.

Python
from mor_sdk import MorClient
from decimal import Decimal
client = MorClient(api_key="sk_live_your_api_key")
# Create a fiscal receipt (Category A merchant — 15% VAT)
receipt = client.receipts.create(
merchant_tin="0012345678",
device_id="device-uuid-here",
items=[
{
"description": "Ethiopian Coffee (1kg)",
"quantity": 2,
"unit_price": "350.00",
"vat_rate": 15,
},
{
"description": "Injera Basket",
"quantity": 1,
"unit_price": "45.00",
"vat_rate": 15,
},
],
payment_method="ETHQR",
total="745.00",
)
print(f"Fiscal Code: {receipt.fiscal_code}")
print(f"Receipt ID: {receipt.id}")

Register a Virtual Fiscal Device

Register and activate a new VFD for your merchant. Supports branch assignment and auto-selection for single-branch merchants.

Python
from mor_sdk import MorClient
client = MorClient(api_key="sk_live_your_api_key")
# Register a new virtual device
device = client.devices.create(
merchant_tin="0012345678",
device_name="POS Terminal #1",
device_type="virtual",
signing_algorithm="ECDSA-P256",
station_id="POS-01",
# branch_id is auto-selected for single-branch merchants
)
print(f"Device ID: {device.id}")
print(f"Serial: {device.serial_number}")
print(f"Status: {device.status}") # pending_activation
# Activate the device
activated = client.devices.activate(device.id)
print(f"Activated: {activated.status}") # active

Handle Webhook Events

Process incoming webhook notifications for receipt events, device status changes, and billing alerts.

Python
from flask import Flask, request, jsonify
import hmac, hashlib
app = Flask(__name__)
WEBHOOK_SECRET = "whsec_your_webhook_secret"
@app.route("/webhooks/mor", methods=["POST"])
def handle_webhook():
# Verify signature (EPAY-3 compliance)
signature = request.headers.get("X-MOR-Signature")
payload = request.get_data()
expected = hmac.new(
WEBHOOK_SECRET.encode(),
payload,
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(signature, expected):
return jsonify({"error": "Invalid signature"}), 401
event = request.get_json()
match event["type"]:
case "receipt.created":
print(f"Receipt {event['data']['fiscal_code']} created")
case "device.suspended":
print(f"Device {event['data']['serial_number']} suspended")
case "billing.payment_failed":
print(f"Payment failed for invoice {event['data']['invoice_id']}")
return jsonify({"received": True}), 200

Generate Z-Report

Close the fiscal day and generate a Z-Report. Mandatory daily per Proclamation 983/2016 (ZRPT-1). Must be submitted within 72 hours (ZRPT-2).

Python
from mor_sdk import MorClient
client = MorClient(api_key="sk_live_your_api_key")
# Get current X-Report (real-time summary)
x_report = client.devices.x_report("device-uuid")
print(f"Receipts today: {x_report.receipt_count}")
print(f"Total sales: ETB {x_report.total_sales}")
# Generate Z-Report (closes fiscal day — ZRPT-1)
z_report = client.devices.z_report("device-uuid")
print(f"Z-Report #{z_report.report_number}")
print(f"Period: {z_report.period_start} to {z_report.period_end}")
print(f"Total: ETB {z_report.grand_total}")
# Z-Reports are immutable after generation (ZRPT-3)
# Sequential numbering enforced — no gaps (ZRPT-4)

Verify Receipt Chain

Validate a receipt's digital signature and chain integrity. Every receipt references its predecessor via previous_receipt_hash (CHAIN-1).

Python
from mor_sdk import MorClient
client = MorClient(api_key="sk_live_your_api_key")
# Verify receipt signature and chain integrity
result = client.receipts.verify("receipt-uuid")
if result.valid:
print("✅ Receipt chain is valid")
print(f" Signature: verified")
print(f" Chain hash: matches previous receipt")
else:
print("❌ Chain validation failed")
print(f" Error: {result.error}")
# Public verification (no API key needed — for customers)
public_result = client.receipts.verify_public(
fiscal_code="MOR-2026-001234"
)
print(f"Public verification: {public_result.valid}")

JavaScript / Fetch API

Integration example using plain JavaScript fetch. Suitable for Node.js, Deno, or browser environments.

JavaScript
// Create a receipt using fetch API
const response = await fetch('https://api.mor.gov.et/v1/receipts', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_your_api_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
merchant_tin: '0012345678',
device_id: 'device-uuid-here',
items: [
{
description: 'Ethiopian Coffee (1kg)',
quantity: 2,
unit_price: '350.00',
vat_rate: 15,
},
],
payment_method: 'ETHQR',
total: '700.00',
}),
});
if (!response.ok) {
const error = await response.json();
// Handle structured error: { error: "CODE", message: "..." }
console.error(`${error.error}: ${error.message}`);
// Handle rate limiting (SEC-7)
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
console.log(`Rate limited. Retry after ${retryAfter}s`);
}
} else {
const receipt = await response.json();
console.log(`Fiscal Code: ${receipt.fiscal_code}`);
}

Need more help integrating?

Check out the full SDK documentation or start with the quickstart guide.