HRS 1:2026 — Annex H forms
H-F2 … H-F5 — Register implementation
Public consultation draft — draft v0.1 — issued 2026-09-07
This is a consultation draft, not an operative standard
The scheme described here is not yet certifying. No certificates have been issued and the Approved Supplier Register is not yet populated. Nothing in this document may be relied on as evidence of certification.
It is published for comment before it is finalised, because a certification standard that cannot be read by the people it governs is not a standard. Clause 12.2 commits us to publishing it; we would rather publish it early and be corrected.
Comments are invited until 2 November 2026. See How to respond. Passages marked ⚖️ are open questions on which we are specifically seeking views. Passages marked 📋 will be reconciled against OIC/SMIIC standards before issue.
This document is a scheme design. It is not a fatwa and does not purport to state Islamic law; questions of Shari'ah are for our Shari'ah Committee, whose rulings will be published with their reasoning.
H-F1 is the OpenAPI specification: H-F1-register-openapi.yaml
— 5 endpoints, 12 schemas, validated.
H-F2 — Register page specification
Content and behaviour. Visual design is a separate brief.
/register/e/{id} — establishment page (the QR destination)
Above the fold — non-negotiable
Someone scanning in a doorway has about three seconds and is probably holding a coat.
| Order | Element |
|---|---|
| 1 | STATUS BANNER — full width, unmissable |
| 2 | Establishment name + address |
| 3 | CLASS — A / B / Provisional, large |
| 4 | For Class B: the disclosure, in the mark's own lock-up — never a footnote |
| 5 | Valid until [date] |
| 6 | Last audited [date] — and whether it was unannounced |
Status banner — six states, visually unmistakable
| Status | Treatment | Wording |
|---|---|---|
active |
Positive, calm | Certified — Class A / Class B |
provisional |
Neutral, clearly not certification | Certification in progress — this is not a halal certification |
suspended |
Alarm | SUSPENDED on [date]. This business is not currently certified. |
suspended_under_appeal |
Alarm | SUSPENDED on [date] — under appeal. Not currently certified. |
withdrawn |
Alarm | CERTIFICATION WITHDRAWN on [date]. |
expired |
Warning | EXPIRED on [date]. Not currently certified. |
⚠️ Never a small grey label. The whole verification mechanism rests on a consumer noticing the difference between certified and suspended in one glance.
Below the fold
Scope, and scope exclusions printed even when none · suppliers (count + link) · declared platform listings · languages verified · status history, full and public · "Report a concern" → Annex G intake · how the register works and that it, not the wall certificate, is authoritative.
Behaviour
- No login, no app, no cookie wall
- Works on a slow mobile connection — the status must render before anything else
- Resolves after expiry and withdrawal, showing that state. A dead link lets a stale certificate keep working
- AZ / RU / EN / AR; status wording translated with equivalent force, not softened
<meta name="robots" content="index,follow">— this page should rank for the business name
/register/s/{id} — supplier page
Same status discipline. Category and route shown in plain language ("Directly assessed by us"
/ "Recognised certificate from [body]"). Species scope. Stunning status ⚖️ once B4.6 is ruled.
supplies_to_count as a number, never a list.
/ — register home
Search by name · filter by class, district, status · map · a plainly-worded explanation of Class A vs Class B · link to the standard, checklist and fee schedule (all free, cl. 12.2) · link to the changes feed and the OpenAPI spec — advertise the integration path.
H-F3 — Süfrə sync service specification
Rule
Süfrə consumes the register. Süfrə is never the master. No halal flag may be set by hand in the app database, ever.
Sync
| Source | GET /register/api/v1/changes?since={last_cursor} |
| Frequency | ≤5 minutes — a suspension must reach the app fast |
| Cursor | Persist occurred_at of the last processed event; resume from it |
| Full reconcile | Nightly, paging all establishments — catches missed events |
| On sync failure | Fail closed. See below |
Fail-closed behaviour — the important part
If the register is unreachable, Süfrə must not keep showing stale certification as current.
| Age of last successful sync | Behaviour |
|---|---|
| < 1 hour | Show cached status normally |
| 1–24 hours | Show status with "last verified [time]" |
| > 24 hours | Suppress the certification badge entirely; show "status could not be verified — check the register" with a link |
Showing a badge from a three-day-old cache is exactly how a suspended restaurant keeps trading on our mark. Failing closed is embarrassing for a few hours; failing open is a credibility event.
Rendering
| Rule | |
|---|---|
Badge shown only where a register record exists and is active or provisional |
|
| Class B badge renders the disclosure inseparably, in the display language | HRS 1 cl. 8.6 |
| Provisional renders variant P wording; never the word halal as a claim | Annex E, E2.2 |
| Uncertified listings marked plainly "not certified" | A directory state, not a scheme tier |
| No intermediate states invented — no "self-declared halal", no "customer-reported halal" | |
Badge links to /register/e/{id} |
|
Süfrə's own listing is a platform_listing subject to cl. 8.5 like any other |
We do not exempt ourselves |
Data Süfrə must not store as truth
Certification status, class, expiry and scope are cached, never authored. An admin UI that can set them is a defect, not a feature — build the admin screens read-only against the register.
In-app reporting
"Report a concern" posts to the Annex G intake (G-F1), including the "I work here" whistleblower path. Süfrə must not triage; it forwards.
H-F4 — QR generation and certificate print integration
QR
| Property | Value |
|---|---|
| Payload | https://sufra.halalekosistem.org/register/e/{id} — plain URL, nothing else |
| Error correction | Level H (30%) — certificates get scuffed, sun-faded and taped |
| Print size | ≥ 25 mm; quiet zone ≥ 4 modules |
| Resolution | ≥ 300 dpi |
| Contrast | Black on white. No logo in the centre, no brand colours, no artistic framing |
| Plain-text URL | Printed beneath, always |
Never encode certificate data in the QR itself. A QR carrying the class and expiry becomes a second source of truth that cannot be updated when status changes — which defeats the entire design. The QR carries an address; the register carries the truth.
Issue pipeline
Decision recorded (by decision-maker ≠ auditor, cl. 12.5)
→ register record created, status=active
→ certificate number assigned HRS-{A|B|P}-{YYYY}-{NNNNNN}
→ QR generated from verify_url
→ certificate PDF rendered from template (E-F3)
→ /e/{id} live BEFORE the certificate is handed over
→ change event emitted
⚠️ The register entry must be live before the certificate leaves our hands. A certificate whose QR 404s on day one destroys confidence in the mechanism permanently.
Reprints and revocation
Reprints keep the same number and QR · lost certificates are not invalidated — the register
governs, so a found certificate showing withdrawn is harmless · on withdrawal the register
updates immediately, so an uncollected certificate tells the truth while signage comes down.
H-F5 — Backup, audit log and tamper evidence
Why this is a control, not just ops
The register's whole value is that it is an append-only public record including suspensions and withdrawals (cl. 11.3). If entries can be silently edited, the register is a marketing list that happens to be online — and the accusation is unanswerable.
Status history is append-only
status_historyrows are inserted, never updated or deleted- A correction is a new row with
reason: "correction of [ref]"— the erroneous row remains visible - Every transition records: actor, timestamp, decision reference, reason category
- Database-level enforcement (trigger or permissions), not application-level only
Tamper evidence
- Each
status_historyrow carries a hash of(previous_hash, entity_id, status, occurred_at, actor) - Chain verifiable end-to-end; a broken chain is detectable
- Daily chain-head published — in the transparency report and via the API — so an external party can confirm history was not rewritten
This is cheap to build now and impossible to retrofit credibly. The first time anyone alleges we quietly un-suspended a client, the chain either answers it or nothing does.
Internal audit log — separate from the public record
Every read of restricted data (audit findings, complaints, reporter identities) and every write. Retained ≥24 months. Reporter-identity access is logged and reviewed — a Technical Committee control, not an IT one.
Backup and availability
| Backups | Nightly, verified by restore test monthly — an untested backup is a hope |
| Retention | ≥24 months, matching cl. 11.3 |
| Off-site copy | Required |
| Uptime target | To be published — if the QR is the verification mechanism, downtime means no certificate in the country can be verified |
| Static fallback | A cached read-only snapshot served if the application is down, clearly marked with its timestamp |
| Status page | Public |
Open
- Uptime target and whether it justifies redundant hosting (Annex H, H6.7).
- Who holds the chain-head publication key, and how rotation is handled.
- Whether the static fallback is regenerated hourly or on every change event.